My Project
geometry_structure.cpp
Go to the documentation of this file.
1 
38 #include "../include/geometry_structure.hpp"
39 #include "../include/adt_structure.hpp"
40 #include <iomanip>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 /*--- Epsilon definition ---*/
44 
45 #define EPSILON 0.000001
46 
47 /*--- Cross product ---*/
48 
49 #define CROSS(dest,v1,v2) \
50 (dest)[0] = (v1)[1]*(v2)[2] - (v1)[2]*(v2)[1]; \
51 (dest)[1] = (v1)[2]*(v2)[0] - (v1)[0]*(v2)[2]; \
52 (dest)[2] = (v1)[0]*(v2)[1] - (v1)[1]*(v2)[0];
53 
54 /*--- Cross product ---*/
55 
56 #define DOT(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2]);
57 
58 /*--- a = b - c ---*/
59 
60 #define SUB(dest,v1,v2) \
61 (dest)[0] = (v1)[0] - (v2)[0]; \
62 (dest)[1] = (v1)[1] - (v2)[1]; \
63 (dest)[2] = (v1)[2] - (v2)[2];
64 
66 
69 
70  nEdge = 0;
71  nPoint = 0;
72  nPointNode = 0;
73  nElem = 0;
74 
75  nElem_Bound = NULL;
76  Tag_to_Marker = NULL;
77  elem = NULL;
78  face = NULL;
79  bound = NULL;
80  node = NULL;
81  edge = NULL;
82  vertex = NULL;
83  nVertex = NULL;
84  newBound = NULL;
85  nNewElem_Bound = NULL;
86  Marker_All_SendRecv = NULL;
87 
90 
91  XCoordList.clear();
92  Xcoord_plane.clear();
93  Ycoord_plane.clear();
94  Zcoord_plane.clear();
95  FaceArea_plane.clear();
96  Plane_points.clear();
97 
98  /*--- Arrays for defining the linear partitioning ---*/
99 
100  starting_node = NULL;
101  ending_node = NULL;
102  npoint_procs = NULL;
103  nPoint_Linear = NULL;
104 
105  /*--- Containers for customized boundary conditions ---*/
106 
107  CustomBoundaryHeatFlux = NULL; //Customized heat flux wall
108  CustomBoundaryTemperature = NULL; //Customized temperature wall
109 
110 }
111 
113 
114  unsigned long iElem, iElem_Bound, iEdge, iFace, iPoint, iVertex;
115  unsigned short iMarker;
116 
117  if (elem != NULL) {
118  for (iElem = 0; iElem < nElem; iElem++)
119  if (elem[iElem] != NULL) delete elem[iElem];
120  delete[] elem;
121  }
122 
123  if (bound != NULL) {
124  for (iMarker = 0; iMarker < nMarker; iMarker++) {
125  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
126  if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound];
127  }
128  if (bound[iMarker] != NULL) delete [] bound[iMarker];
129  }
130  delete [] bound;
131  }
132 
133  if (face != NULL) {
134  for (iFace = 0; iFace < nFace; iFace ++)
135  if (face[iFace] != NULL) delete face[iFace];
136  delete[] face;
137  }
138 
139  if (node != NULL) {
140  for (iPoint = 0; iPoint < nPointNode; iPoint ++)
141  if (node[iPoint] != NULL) delete node[iPoint];
142  delete[] node;
143  }
144 
145 
146  if (edge != NULL) {
147  for (iEdge = 0; iEdge < nEdge; iEdge ++)
148  if (edge[iEdge] != NULL) delete edge[iEdge];
149  delete[] edge;
150  }
151 
152  if (vertex != NULL) {
153  for (iMarker = 0; iMarker < nMarker; iMarker++) {
154  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
155  if (vertex[iMarker][iVertex] != NULL) delete vertex[iMarker][iVertex];
156  }
157  if (vertex[iMarker] != NULL) delete [] vertex[iMarker];
158  }
159  delete [] vertex;
160  }
161 
162  if (newBound != NULL) {
163  for (iMarker = 0; iMarker < nMarker; iMarker++) {
164  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
165  if (newBound[iMarker][iElem_Bound] != NULL) delete [] newBound[iMarker][iElem_Bound];
166  }
167  delete[] newBound[iMarker];
168  }
169  delete[] newBound;
170  }
171 
172  if (nElem_Bound != NULL) delete [] nElem_Bound;
173  if (nVertex != NULL) delete [] nVertex;
174  if (nNewElem_Bound != NULL) delete [] nNewElem_Bound;
175  if (Marker_All_SendRecv != NULL) delete [] Marker_All_SendRecv;
176  if (Tag_to_Marker != NULL) delete [] Tag_to_Marker;
177 
178  if (starting_node != NULL) delete [] starting_node;
179  if (ending_node != NULL) delete [] ending_node;
180  if (npoint_procs != NULL) delete [] npoint_procs;
181  if (nPoint_Linear != NULL) delete [] nPoint_Linear;
182 
183  if(CustomBoundaryHeatFlux != NULL){
184  for(iMarker=0; iMarker < nMarker; iMarker++){
185  if (CustomBoundaryHeatFlux[iMarker] != NULL) delete [] CustomBoundaryHeatFlux[iMarker];
186  }
187  delete [] CustomBoundaryHeatFlux;
188  }
189 
190  if(CustomBoundaryTemperature != NULL){
191  for(iMarker=0; iMarker < nMarker; iMarker++){
192  if(CustomBoundaryTemperature[iMarker] != NULL) delete [] CustomBoundaryTemperature[iMarker];
193  }
194  delete [] CustomBoundaryTemperature;
195  }
196 
197 }
198 
200  su2double CrossProduct[3], iVector[3], jVector[3], distance, modulus;
201  unsigned short iDim;
202 
203  for (iDim = 0; iDim < 3; iDim ++) {
204  iVector[iDim] = jCoord[iDim] - iCoord[iDim];
205  jVector[iDim] = kCoord[iDim] - iCoord[iDim];
206  }
207 
208  CrossProduct[0] = iVector[1]*jVector[2] - iVector[2]*jVector[1];
209  CrossProduct[1] = iVector[2]*jVector[0] - iVector[0]*jVector[2];
210  CrossProduct[2] = iVector[0]*jVector[1] - iVector[1]*jVector[0];
211 
212  modulus = sqrt(CrossProduct[0]*CrossProduct[0]+CrossProduct[1]*CrossProduct[1]+CrossProduct[2]*CrossProduct[2]);
213 
214  distance = 0.0;
215  for (iDim = 0; iDim < 3; iDim ++)
216  distance += CrossProduct[iDim]*(Coord[iDim]-iCoord[iDim]);
217  distance /= modulus;
218 
219  return distance;
220 
221 }
222 
223 long CGeometry::FindEdge(unsigned long first_point, unsigned long second_point) {
224  unsigned long iPoint = 0;
225  unsigned short iNode;
226  for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) {
227  iPoint = node[first_point]->GetPoint(iNode);
228  if (iPoint == second_point) break;
229  }
230 
231  if (iPoint == second_point) return node[first_point]->GetEdge(iNode);
232  else {
233  char buf[100];
234  SPRINTF(buf, "Can't find the edge that connects %lu and %lu.", first_point, second_point);
236  return 0;
237  }
238 }
239 
240 bool CGeometry::CheckEdge(unsigned long first_point, unsigned long second_point) {
241  unsigned long iPoint = 0;
242  unsigned short iNode;
243  for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) {
244  iPoint = node[first_point]->GetPoint(iNode);
245  if (iPoint == second_point) break;
246  }
247 
248  if (iPoint == second_point) return true;
249  else return false;
250 
251 }
252 
254  unsigned long iPoint, jPoint;
255  long iEdge;
256  unsigned short jNode, iNode;
257  long TestEdge = 0;
258 
259  nEdge = 0;
260  for (iPoint = 0; iPoint < nPoint; iPoint++)
261  for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) {
262  jPoint = node[iPoint]->GetPoint(iNode);
263  for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++)
264  if (node[jPoint]->GetPoint(jNode) == iPoint) {
265  TestEdge = node[jPoint]->GetEdge(jNode);
266  break;
267  }
268  if (TestEdge == -1) {
269  node[iPoint]->SetEdge(nEdge, iNode);
270  node[jPoint]->SetEdge(nEdge, jNode);
271  nEdge++;
272  }
273  }
274 
275  edge = new CEdge*[nEdge];
276 
277  for (iPoint = 0; iPoint < nPoint; iPoint++)
278  for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) {
279  jPoint = node[iPoint]->GetPoint(iNode);
280  iEdge = FindEdge(iPoint, jPoint);
281  if (iPoint < jPoint) edge[iEdge] = new CEdge(iPoint, jPoint, nDim);
282  }
283 }
284 
286  // unsigned long iPoint, jPoint, iFace;
287  // unsigned short jNode, iNode;
288  // long TestFace = 0;
289  //
290  // nFace = 0;
291  // for (iPoint = 0; iPoint < nPoint; iPoint++)
292  // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) {
293  // jPoint = node[iPoint]->GetPoint(iNode);
294  // for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++)
295  // if (node[jPoint]->GetPoint(jNode) == iPoint) {
296  // TestFace = node[jPoint]->GetFace(jNode);
297  // break;
298  // }
299  // if (TestFace == -1) {
300  // node[iPoint]->SetFace(nFace, iNode);
301  // node[jPoint]->SetFace(nFace, jNode);
302  // nFace++;
303  // }
304  // }
305  //
306  // face = new CFace*[nFace];
307  //
308  // for (iPoint = 0; iPoint < nPoint; iPoint++)
309  // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) {
310  // jPoint = node[iPoint]->GetPoint(iNode);
311  // iFace = FindFace(iPoint, jPoint);
312  // if (iPoint < jPoint) face[iFace] = new CFace(iPoint, jPoint, nDim);
313  // }
314 }
315 
317 
318  ofstream para_file;
319 
320  para_file.open("test_geometry.dat", ios::out);
321 
322  su2double *Normal = new su2double[nDim];
323 
324  for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) {
325  para_file << "Edge index: " << iEdge << endl;
326  para_file << " Point index: " << edge[iEdge]->GetNode(0) << "\t" << edge[iEdge]->GetNode(1) << endl;
327  edge[iEdge]->GetNormal(Normal);
328  para_file << " Face normal : ";
329  for (unsigned short iDim = 0; iDim < nDim; iDim++)
330  para_file << Normal[iDim] << "\t";
331  para_file << endl;
332  }
333 
334  para_file << endl;
335  para_file << endl;
336  para_file << endl;
337  para_file << endl;
338 
339  for (unsigned short iMarker =0; iMarker < nMarker; iMarker++) {
340  para_file << "Marker index: " << iMarker << endl;
341  for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
342  para_file << " Vertex index: " << iVertex << endl;
343  para_file << " Point index: " << vertex[iMarker][iVertex]->GetNode() << endl;
344  para_file << " Point coordinates : ";
345  for (unsigned short iDim = 0; iDim < nDim; iDim++) {
346  para_file << node[vertex[iMarker][iVertex]->GetNode()]->GetCoord(iDim) << "\t";}
347  para_file << endl;
348  vertex[iMarker][iVertex]->GetNormal(Normal);
349  para_file << " Face normal : ";
350  for (unsigned short iDim = 0; iDim < nDim; iDim++)
351  para_file << Normal[iDim] << "\t";
352  para_file << endl;
353  }
354  }
355 
356  delete [] Normal;
357 
358 }
359 
360 void CGeometry::SetSpline(vector<su2double> &x, vector<su2double> &y, unsigned long n, su2double yp1, su2double ypn, vector<su2double> &y2) {
361  unsigned long i, k;
362  su2double p, qn, sig, un, *u;
363 
364  u = new su2double [n];
365 
366  if (yp1 > 0.99e30) // The lower boundary condition is set either to be "nat
367  y2[0]=u[0]=0.0; // -ural"
368  else { // or else to have a specified first derivative.
369  y2[0] = -0.5;
370  u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1);
371  }
372 
373  for (i=2; i<=n-1; i++) { // This is the decomposition loop of the tridiagonal al-
374  sig=(x[i-1]-x[i-2])/(x[i]-x[i-2]); // gorithm. y2 and u are used for tem-
375  p=sig*y2[i-2]+2.0; // porary storage of the decomposed
376  y2[i-1]=(sig-1.0)/p; // factors.
377 
378  su2double a1 = (y[i]-y[i-1])/(x[i]-x[i-1]); if (x[i] == x[i-1]) a1 = 1.0;
379  su2double a2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]); if (x[i-1] == x[i-2]) a2 = 1.0;
380  u[i-1]= a1 - a2;
381  u[i-1]=(6.0*u[i-1]/(x[i]-x[i-2])-sig*u[i-2])/p;
382 
383  }
384 
385  if (ypn > 0.99e30) // The upper boundary condition is set either to be
386  qn=un=0.0; // "natural"
387  else { // or else to have a specified first derivative.
388  qn=0.5;
389  un=(3.0/(x[n-1]-x[n-2]))*(ypn-(y[n-1]-y[n-2])/(x[n-1]-x[n-2]));
390  }
391  y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0);
392  for (k=n-1; k>=1; k--) // This is the backsubstitution loop of the tridiagonal
393  y2[k-1]=y2[k-1]*y2[k]+u[k-1]; // algorithm.
394 
395  delete[] u;
396 
397 }
398 
399 su2double CGeometry::GetSpline(vector<su2double>&xa, vector<su2double>&ya, vector<su2double>&y2a, unsigned long n, su2double x) {
400  unsigned long klo, khi, k;
401  su2double h, b, a, y;
402 
403  if (x < xa[0]) x = xa[0]; // Clip max and min values
404  if (x > xa[n-1]) x = xa[n-1];
405 
406  klo = 1; // We will find the right place in the table by means of
407  khi = n; // bisection. This is optimal if sequential calls to this
408  while (khi-klo > 1) { // routine are at random values of x. If sequential calls
409  k = (khi+klo) >> 1; // are in order, and closely spaced, one would do better
410  if (xa[k-1] > x) khi = k; // to store previous values of klo and khi and test if
411  else klo=k; // they remain appropriate on the next call.
412  } // klo and khi now bracket the input value of x
413  h = xa[khi-1] - xa[klo-1];
414  if (h == 0.0) h = EPS; // cout << "Bad xa input to routine splint" << endl; // The xa?s must be distinct.
415  a = (xa[khi-1]-x)/h;
416  b = (x-xa[klo-1])/h; // Cubic spline polynomial is now evaluated.
417  y = a*ya[klo-1]+b*ya[khi-1]+((a*a*a-a)*y2a[klo-1]+(b*b*b-b)*y2a[khi-1])*(h*h)/6.0;
418 
419  return y;
420 }
421 
422 bool CGeometry::SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1,
423  su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp) {
424  su2double u[3], v[3], Denominator, Numerator, Aux, ModU;
425  su2double epsilon = 1E-6; // An epsilon is added to eliminate, as much as possible, the posibility of a line that intersects a point
426  unsigned short iDim;
427 
428  for (iDim = 0; iDim < 3; iDim++) {
429  u[iDim] = Segment_P1[iDim] - Segment_P0[iDim];
430  v[iDim] = (Plane_P0[iDim]+epsilon) - Segment_P0[iDim];
431  }
432 
433  ModU = sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2]);
434 
435  Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2];
436  Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2];
437 
438  if (fabs(Denominator) <= 0.0) return (false); // No intersection.
439 
440  Aux = Numerator / Denominator;
441 
442  if (Aux < 0.0 || Aux > 1.0) return (false); // No intersection.
443 
444  for (iDim = 0; iDim < 3; iDim++)
445  Intersection[iDim] = Segment_P0[iDim] + Aux * u[iDim];
446 
447 
448  /*--- Check that the intersection is in the segment ---*/
449 
450  for (iDim = 0; iDim < 3; iDim++) {
451  u[iDim] = Segment_P0[iDim] - Intersection[iDim];
452  v[iDim] = Segment_P1[iDim] - Intersection[iDim];
453  }
454 
455  Variable_Interp = Variable_P0 + (Variable_P1 - Variable_P0)*sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2])/ModU;
456 
457  Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2];
458  Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2];
459 
460  Aux = Numerator * Denominator;
461 
462  if (Aux > 0.0) return (false); // Intersection outside the segment.
463 
464  return (true);
465 
466 }
467 
469  su2double vert0[3], su2double vert1[3], su2double vert2[3],
470  su2double *intersect) {
471 
472  su2double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
473  su2double det, inv_det, t, u, v;
474 
475  /*--- Find vectors for two edges sharing vert0 ---*/
476 
477  SUB(edge1, vert1, vert0);
478  SUB(edge2, vert2, vert0);
479 
480  /*--- Begin calculating determinant - also used to calculate U parameter ---*/
481 
482  CROSS(pvec, dir, edge2);
483 
484  /*--- If determinant is near zero, ray lies in plane of triangle ---*/
485 
486  det = DOT(edge1, pvec);
487 
488 
489  if (det > -EPSILON && det < EPSILON) return(false);
490 
491  inv_det = 1.0 / det;
492 
493  /*--- Calculate distance from vert0 to ray origin ---*/
494 
495  SUB(tvec, orig, vert0);
496 
497  /*--- Calculate U parameter and test bounds ---*/
498 
499  u = inv_det * DOT(tvec, pvec);
500 
501  if (u < 0.0 || u > 1.0) return(false);
502 
503  /*--- prepare to test V parameter ---*/
504 
505  CROSS(qvec, tvec, edge1);
506 
507  /*--- Calculate V parameter and test bounds ---*/
508 
509  v = inv_det * DOT(dir, qvec);
510 
511  if (v < 0.0 || u + v > 1.0) return(false);
512 
513  /*--- Calculate t, ray intersects triangle ---*/
514 
515  t = inv_det * DOT(edge2, qvec);
516 
517  /*--- Compute the intersection point in cartesian coordinates ---*/
518 
519  intersect[0] = orig[0] + (t * dir[0]);
520  intersect[1] = orig[1] + (t * dir[1]);
521  intersect[2] = orig[2] + (t * dir[2]);
522 
523  return (true);
524 
525 }
526 
527 bool CGeometry::SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2]) {
528 
529  su2double det, diff0_A, diff0_B, diff1_A, diff1_B, intersect[2];
530 
531  diff0_A = point0[0] - point1[0];
532  diff1_A = point0[1] - point1[1];
533 
534  diff0_B = vert0[0] - vert1[0];
535  diff1_B = vert0[1] - vert1[1];
536 
537  det = (diff0_A)*(diff1_B) - (diff1_A)*(diff0_B);
538 
539  if (det == 0) return false;
540 
541  /*--- Compute point of intersection ---*/
542 
543  intersect[0] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff0_B
544  -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff0_A)/det;
545 
546  intersect[1] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff1_B
547  -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff1_A)/det;
548 
549 
550  /*--- Check that the point is between the two surface points ---*/
551 
552  su2double dist0, dist1, length;
553 
554  dist0 = (intersect[0] - point0[0])*(intersect[0] - point0[0])
555  +(intersect[1] - point0[1])*(intersect[1] - point0[1]);
556 
557  dist1 = (intersect[0] - point1[0])*(intersect[0] - point1[0])
558  +(intersect[1] - point1[1])*(intersect[1] - point1[1]);
559 
560  length = diff0_A*diff0_A
561  +diff1_A*diff1_A;
562 
563  if ( (dist0 > length) || (dist1 > length) ) {
564  return false;
565  }
566 
567  return true;
568 }
569 
571  su2double vert0[3], su2double vert1[3], su2double vert2[3]) {
572 
573  su2double dir[3], intersect[3], u[3], v[3], edge1[3], edge2[3], Plane_Normal[3], Denominator, Numerator, Aux;
574 
575  SUB(dir, point1, point0);
576 
577  if (RayIntersectsTriangle(point0, dir, vert0, vert1, vert2, intersect)) {
578 
579  /*--- Check that the intersection is in the segment ---*/
580 
581  SUB(u, point0, intersect);
582  SUB(v, point1, intersect);
583 
584  SUB(edge1, vert1, vert0);
585  SUB(edge2, vert2, vert0);
586  CROSS(Plane_Normal, edge1, edge2);
587 
588  Denominator = DOT(Plane_Normal, u);
589  Numerator = DOT(Plane_Normal, v);
590 
591  Aux = Numerator * Denominator;
592 
593  /*--- Intersection outside the segment ---*/
594 
595  if (Aux > 0.0) return (false);
596 
597  }
598  else {
599 
600  /*--- No intersection with the ray ---*/
601 
602  return (false);
603 
604  }
605 
606  /*--- Intersection inside the segment ---*/
607 
608  return (true);
609 
610 }
611 
613  su2double MinXCoord, su2double MaxXCoord,
614  su2double MinYCoord, su2double MaxYCoord,
615  su2double MinZCoord, su2double MaxZCoord,
616  su2double *FlowVariable,
617  vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil,
618  vector<su2double> &Zcoord_Airfoil, vector<su2double> &Variable_Airfoil,
619  bool original_surface, CConfig *config) {
620 
622 
623  unsigned short iMarker, iNode, jNode, iDim, Index = 0;
624  bool intersect;
625  long Next_Edge = 0;
626  unsigned long iPoint, jPoint, iElem, Trailing_Point, Airfoil_Point, iVertex, iEdge, PointIndex, jEdge;
627  su2double Segment_P0[3] = {0.0, 0.0, 0.0}, Segment_P1[3] = {0.0, 0.0, 0.0}, Variable_P0 = 0.0, Variable_P1 = 0.0, Intersection[3] = {0.0, 0.0, 0.0}, Trailing_Coord,
628  *VarCoord = NULL, Variable_Interp, v1[3] = {0.0, 0.0, 0.0}, v3[3] = {0.0, 0.0, 0.0}, CrossProduct = 1.0;
629  bool Found_Edge;
630  passivedouble Dist_Value;
631  vector<su2double> Xcoord_Index0, Ycoord_Index0, Zcoord_Index0, Variable_Index0, Xcoord_Index1, Ycoord_Index1, Zcoord_Index1, Variable_Index1;
632  vector<unsigned long> IGlobalID_Index0, JGlobalID_Index0, IGlobalID_Index1, JGlobalID_Index1, IGlobalID_Airfoil, JGlobalID_Airfoil;
633  vector<unsigned short> Conection_Index0, Conection_Index1;
634  vector<unsigned long> Duplicate;
635  vector<unsigned long>::iterator it;
636  su2double **Coord_Variation = NULL;
637  vector<su2double> XcoordExtra, YcoordExtra, ZcoordExtra, VariableExtra;
638  vector<unsigned long> IGlobalIDExtra, JGlobalIDExtra;
639  vector<bool> AddExtra;
640  unsigned long EdgeDonor;
641  bool FoundEdge;
642 
643 #ifdef HAVE_MPI
644  unsigned long nLocalEdge, MaxLocalEdge, *Buffer_Send_nEdge, *Buffer_Receive_nEdge, nBuffer_Coord, nBuffer_Variable, nBuffer_GlobalID;
645  int nProcessor, iProcessor;
646  su2double *Buffer_Send_Coord, *Buffer_Receive_Coord;
647  su2double *Buffer_Send_Variable, *Buffer_Receive_Variable;
648  unsigned long *Buffer_Send_GlobalID, *Buffer_Receive_GlobalID;
649 #endif
650 
651  Xcoord_Airfoil.clear();
652  Ycoord_Airfoil.clear();
653  Zcoord_Airfoil.clear();
654  Variable_Airfoil.clear();
655  IGlobalID_Airfoil.clear();
656  JGlobalID_Airfoil.clear();
657 
658  /*--- Set the right plane in 2D (note the change in Y-Z plane) ---*/
659 
660  if (nDim == 2) {
661  Plane_P0[0] = 0.0; Plane_P0[1] = 0.0; Plane_P0[2] = 0.0;
662  Plane_Normal[0] = 0.0; Plane_Normal[1] = 1.0; Plane_Normal[2] = 0.0;
663  }
664 
665  /*--- Grid movement is stored using a vertices information,
666  we should go from vertex to points ---*/
667 
668  if (original_surface == false) {
669 
670  Coord_Variation = new su2double *[nPoint];
671  for (iPoint = 0; iPoint < nPoint; iPoint++)
672  Coord_Variation[iPoint] = new su2double [nDim];
673 
674  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
675  if (config->GetMarker_All_GeoEval(iMarker) == YES) {
676  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
677  VarCoord = vertex[iMarker][iVertex]->GetVarCoord();
678  iPoint = vertex[iMarker][iVertex]->GetNode();
679  for (iDim = 0; iDim < nDim; iDim++)
680  Coord_Variation[iPoint][iDim] = VarCoord[iDim];
681  }
682  }
683  }
684 
685  }
686 
687  for (iMarker = 0; iMarker < nMarker; iMarker++) {
688 
689  if (config->GetMarker_All_GeoEval(iMarker) == YES) {
690 
691  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) {
692 
693  PointIndex=0;
694 
695  /*--- To decide if an element is going to be used or not should be done element based,
696  The first step is to compute and average coordinate for the element ---*/
697 
698  su2double AveXCoord = 0.0;
699  su2double AveYCoord = 0.0;
700  su2double AveZCoord = 0.0;
701 
702  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
703  iPoint = bound[iMarker][iElem]->GetNode(iNode);
704  AveXCoord += node[iPoint]->GetCoord(0);
705  AveYCoord += node[iPoint]->GetCoord(1);
706  if (nDim == 3) AveZCoord += node[iPoint]->GetCoord(2);
707  }
708 
709  AveXCoord /= su2double(bound[iMarker][iElem]->GetnNodes());
710  AveYCoord /= su2double(bound[iMarker][iElem]->GetnNodes());
711  AveZCoord /= su2double(bound[iMarker][iElem]->GetnNodes());
712 
713  /*--- To only cut one part of the nacelle based on the cross product
714  of the normal to the plane and a vector that connect the point
715  with the center line ---*/
716 
717  CrossProduct = 1.0;
718 
719  if (config->GetGeo_Description() == NACELLE) {
720 
721  su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180;
722  su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180;
723 
724  /*--- Translate to the origin ---*/
725 
726  su2double XCoord_Trans = AveXCoord - config->GetNacelleLocation(0);
727  su2double YCoord_Trans = AveYCoord - config->GetNacelleLocation(1);
728  su2double ZCoord_Trans = AveZCoord - config->GetNacelleLocation(2);
729 
730  /*--- Apply tilt angle ---*/
731 
732  su2double XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle);
733  su2double YCoord_Trans_Tilt = YCoord_Trans;
734  su2double ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle);
735 
736  /*--- Apply toe angle ---*/
737 
738  su2double YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle);
739  su2double ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt;
740 
741  /*--- Undo plane rotation, we have already rotated the nacelle ---*/
742 
743  /*--- Undo tilt angle ---*/
744 
745  su2double XPlane_Normal_Tilt = Plane_Normal[0]*cos(-Tilt_Angle) + Plane_Normal[2]*sin(-Tilt_Angle);
746  su2double YPlane_Normal_Tilt = Plane_Normal[1];
747  su2double ZPlane_Normal_Tilt = Plane_Normal[2]*cos(-Tilt_Angle) - Plane_Normal[0]*sin(-Tilt_Angle);
748 
749  /*--- Undo toe angle ---*/
750 
751  su2double YPlane_Normal_Tilt_Toe = XPlane_Normal_Tilt*sin(-Toe_Angle) + YPlane_Normal_Tilt*cos(-Toe_Angle);
752  su2double ZPlane_Normal_Tilt_Toe = ZPlane_Normal_Tilt;
753 
754 
755  v1[1] = YCoord_Trans_Tilt_Toe - 0.0;
756  v1[2] = ZCoord_Trans_Tilt_Toe - 0.0;
757  v3[0] = v1[1]*ZPlane_Normal_Tilt_Toe-v1[2]*YPlane_Normal_Tilt_Toe;
758  CrossProduct = v3[0] * 1.0;
759 
760  }
761 
762  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
763  iPoint = bound[iMarker][iElem]->GetNode(iNode);
764 
765  for (jNode = 0; jNode < bound[iMarker][iElem]->GetnNodes(); jNode++) {
766  jPoint = bound[iMarker][iElem]->GetNode(jNode);
767 
768  /*--- CrossProduct concept is delicated because it allows triangles where only one side is divided by a plane.
769  that is going against the concept that all the triangles are divided twice and causes probelms because
770  Xcoord_Index0.size() > Xcoord_Index1.size()! ---*/
771 
772  if ((jPoint > iPoint) && (CrossProduct >= 0.0)
773  && ((AveXCoord > MinXCoord) && (AveXCoord < MaxXCoord))
774  && ((AveYCoord > MinYCoord) && (AveYCoord < MaxYCoord))
775  && ((AveZCoord > MinZCoord) && (AveZCoord < MaxZCoord))) {
776 
777  Segment_P0[0] = 0.0; Segment_P0[1] = 0.0; Segment_P0[2] = 0.0; Variable_P0 = 0.0;
778  Segment_P1[0] = 0.0; Segment_P1[1] = 0.0; Segment_P1[2] = 0.0; Variable_P1 = 0.0;
779 
780 
781  for (iDim = 0; iDim < nDim; iDim++) {
782  if (original_surface == true) {
783  Segment_P0[iDim] = node[iPoint]->GetCoord(iDim);
784  Segment_P1[iDim] = node[jPoint]->GetCoord(iDim);
785  }
786  else {
787  Segment_P0[iDim] = node[iPoint]->GetCoord(iDim) + Coord_Variation[iPoint][iDim];
788  Segment_P1[iDim] = node[jPoint]->GetCoord(iDim) + Coord_Variation[jPoint][iDim];
789  }
790  }
791 
792  if (FlowVariable != NULL) {
793  Variable_P0 = FlowVariable[iPoint];
794  Variable_P1 = FlowVariable[jPoint];
795  }
796 
797  /*--- In 2D add the points directly (note the change between Y and Z coordinate) ---*/
798 
799  if (nDim == 2) {
800  Xcoord_Index0.push_back(Segment_P0[0]); Xcoord_Index1.push_back(Segment_P1[0]);
801  Ycoord_Index0.push_back(Segment_P0[2]); Ycoord_Index1.push_back(Segment_P1[2]);
802  Zcoord_Index0.push_back(Segment_P0[1]); Zcoord_Index1.push_back(Segment_P1[1]);
803  Variable_Index0.push_back(Variable_P0); Variable_Index1.push_back(Variable_P1);
804  IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); IGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex());
805  JGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex());
806  PointIndex++;
807  }
808 
809  /*--- In 3D compute the intersection ---*/
810 
811  else if (nDim == 3) {
812  intersect = SegmentIntersectsPlane(Segment_P0, Segment_P1, Variable_P0, Variable_P1, Plane_P0, Plane_Normal, Intersection, Variable_Interp);
813  if (intersect == true) {
814  if (PointIndex == 0) {
815  Xcoord_Index0.push_back(Intersection[0]);
816  Ycoord_Index0.push_back(Intersection[1]);
817  Zcoord_Index0.push_back(Intersection[2]);
818  Variable_Index0.push_back(Variable_Interp);
819  IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex());
820  JGlobalID_Index0.push_back(node[jPoint]->GetGlobalIndex());
821  }
822  if (PointIndex == 1) {
823  Xcoord_Index1.push_back(Intersection[0]);
824  Ycoord_Index1.push_back(Intersection[1]);
825  Zcoord_Index1.push_back(Intersection[2]);
826  Variable_Index1.push_back(Variable_Interp);
827  IGlobalID_Index1.push_back(node[iPoint]->GetGlobalIndex());
828  JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex());
829  }
830  PointIndex++;
831  }
832  }
833 
834  }
835  }
836  }
837 
838  }
839  }
840  }
841 
842  if (original_surface == false) {
843  for (iPoint = 0; iPoint < nPoint; iPoint++)
844  delete [] Coord_Variation[iPoint];
845  delete [] Coord_Variation;
846  }
847 
848 #ifdef HAVE_MPI
849 
850  /*--- Copy the coordinates of all the points in the plane to the master node ---*/
851 
852  nLocalEdge = 0, MaxLocalEdge = 0;
853  nProcessor = size;
854 
855  Buffer_Send_nEdge = new unsigned long [1];
856  Buffer_Receive_nEdge = new unsigned long [nProcessor];
857 
858  nLocalEdge = Xcoord_Index0.size();
859 
860  Buffer_Send_nEdge[0] = nLocalEdge;
861 
862  SU2_MPI::Allreduce(&nLocalEdge, &MaxLocalEdge, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
863  SU2_MPI::Allgather(Buffer_Send_nEdge, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nEdge, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
864 
865  Buffer_Send_Coord = new su2double [MaxLocalEdge*6];
866  Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalEdge*6];
867 
868  Buffer_Send_Variable = new su2double [MaxLocalEdge*2];
869  Buffer_Receive_Variable = new su2double [nProcessor*MaxLocalEdge*2];
870 
871  Buffer_Send_GlobalID = new unsigned long [MaxLocalEdge*4];
872  Buffer_Receive_GlobalID = new unsigned long [nProcessor*MaxLocalEdge*4];
873 
874  nBuffer_Coord = MaxLocalEdge*6;
875  nBuffer_Variable = MaxLocalEdge*2;
876  nBuffer_GlobalID = MaxLocalEdge*4;
877 
878  for (iEdge = 0; iEdge < nLocalEdge; iEdge++) {
879  Buffer_Send_Coord[iEdge*6 + 0] = Xcoord_Index0[iEdge];
880  Buffer_Send_Coord[iEdge*6 + 1] = Ycoord_Index0[iEdge];
881  Buffer_Send_Coord[iEdge*6 + 2] = Zcoord_Index0[iEdge];
882  Buffer_Send_Coord[iEdge*6 + 3] = Xcoord_Index1[iEdge];
883  Buffer_Send_Coord[iEdge*6 + 4] = Ycoord_Index1[iEdge];
884  Buffer_Send_Coord[iEdge*6 + 5] = Zcoord_Index1[iEdge];
885 
886  Buffer_Send_Variable[iEdge*2 + 0] = Variable_Index0[iEdge];
887  Buffer_Send_Variable[iEdge*2 + 1] = Variable_Index1[iEdge];
888 
889  Buffer_Send_GlobalID[iEdge*4 + 0] = IGlobalID_Index0[iEdge];
890  Buffer_Send_GlobalID[iEdge*4 + 1] = JGlobalID_Index0[iEdge];
891  Buffer_Send_GlobalID[iEdge*4 + 2] = IGlobalID_Index1[iEdge];
892  Buffer_Send_GlobalID[iEdge*4 + 3] = JGlobalID_Index1[iEdge];
893  }
894 
895  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD);
896  SU2_MPI::Allgather(Buffer_Send_Variable, nBuffer_Variable, MPI_DOUBLE, Buffer_Receive_Variable, nBuffer_Variable, MPI_DOUBLE, MPI_COMM_WORLD);
897  SU2_MPI::Allgather(Buffer_Send_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
898 
899  /*--- Clean the vectors before adding the new vertices only to the master node ---*/
900 
901  Xcoord_Index0.clear(); Xcoord_Index1.clear();
902  Ycoord_Index0.clear(); Ycoord_Index1.clear();
903  Zcoord_Index0.clear(); Zcoord_Index1.clear();
904  Variable_Index0.clear(); Variable_Index1.clear();
905  IGlobalID_Index0.clear(); IGlobalID_Index1.clear();
906  JGlobalID_Index0.clear(); JGlobalID_Index1.clear();
907 
908  /*--- Copy the boundary to the master node vectors ---*/
909 
910  if (rank == MASTER_NODE) {
911  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) {
912  for (iEdge = 0; iEdge < Buffer_Receive_nEdge[iProcessor]; iEdge++) {
913  Xcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 0] );
914  Ycoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 1] );
915  Zcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 2] );
916  Xcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 3] );
917  Ycoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 4] );
918  Zcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 5] );
919 
920  Variable_Index0.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 0] );
921  Variable_Index1.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 1] );
922 
923  IGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 0] );
924  JGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 1] );
925  IGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 2] );
926  JGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 3] );
927 
928  }
929  }
930  }
931 
932  delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord;
933  delete[] Buffer_Send_Variable; delete[] Buffer_Receive_Variable;
934  delete[] Buffer_Send_GlobalID; delete[] Buffer_Receive_GlobalID;
935  delete[] Buffer_Send_nEdge; delete[] Buffer_Receive_nEdge;
936 
937 #endif
938 
939  if ((rank == MASTER_NODE) && (Xcoord_Index0.size() != 0)) {
940 
941  /*--- Remove singular edges ---*/
942 
943  bool Remove;
944 
945  do { Remove = false;
946  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
947 
948  if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge])) ||
949  ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]))) {
950 
951  Xcoord_Index0.erase (Xcoord_Index0.begin() + iEdge);
952  Ycoord_Index0.erase (Ycoord_Index0.begin() + iEdge);
953  Zcoord_Index0.erase (Zcoord_Index0.begin() + iEdge);
954  Variable_Index0.erase (Variable_Index0.begin() + iEdge);
955  IGlobalID_Index0.erase (IGlobalID_Index0.begin() + iEdge);
956  JGlobalID_Index0.erase (JGlobalID_Index0.begin() + iEdge);
957 
958  Xcoord_Index1.erase (Xcoord_Index1.begin() + iEdge);
959  Ycoord_Index1.erase (Ycoord_Index1.begin() + iEdge);
960  Zcoord_Index1.erase (Zcoord_Index1.begin() + iEdge);
961  Variable_Index1.erase (Variable_Index1.begin() + iEdge);
962  IGlobalID_Index1.erase (IGlobalID_Index1.begin() + iEdge);
963  JGlobalID_Index1.erase (JGlobalID_Index1.begin() + iEdge);
964 
965  Remove = true; break;
966  }
967  if (Remove) break;
968  }
969  } while (Remove == true);
970 
971  /*--- Remove repeated edges computing distance, this could happend because the MPI ---*/
972 
973  do { Remove = false;
974  for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) {
975  for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) {
976 
977  /*--- Edges with the same orientation ---*/
978 
979  if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) ||
980  ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]))) &&
981  (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) ||
982  ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge])))) {
983 
984  Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge);
985  Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge);
986  Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge);
987  Variable_Index0.erase (Variable_Index0.begin() + jEdge);
988  IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge);
989  JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge);
990 
991  Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge);
992  Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge);
993  Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge);
994  Variable_Index1.erase (Variable_Index1.begin() + jEdge);
995  IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge);
996  JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge);
997 
998  Remove = true; break;
999 
1000  }
1001 
1002  /*--- Edges with oposite orientation ---*/
1003 
1004  if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) ||
1005  ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]))) &&
1006  (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) ||
1007  ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge])))) {
1008 
1009  Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge);
1010  Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge);
1011  Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge);
1012  Variable_Index0.erase (Variable_Index0.begin() + jEdge);
1013  IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge);
1014  JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge);
1015 
1016  Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge);
1017  Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge);
1018  Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge);
1019  Variable_Index1.erase (Variable_Index1.begin() + jEdge);
1020  IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge);
1021  JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge);
1022 
1023  Remove = true; break;
1024  }
1025  if (Remove) break;
1026  }
1027  if (Remove) break;
1028  }
1029 
1030  } while (Remove == true);
1031 
1032  if (Xcoord_Index0.size() != 1) {
1033 
1034  /*--- Rotate from the Y-Z plane to the X-Z plane to reuse the rest of subroutines ---*/
1035 
1036  if (config->GetGeo_Description() == FUSELAGE) {
1037  su2double Angle = -0.5*PI_NUMBER;
1038  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
1039  su2double XCoord = Xcoord_Index0[iEdge]*cos(Angle) - Ycoord_Index0[iEdge]*sin(Angle);
1040  su2double YCoord = Ycoord_Index0[iEdge]*cos(Angle) + Xcoord_Index0[iEdge]*sin(Angle);
1041  su2double ZCoord = Zcoord_Index0[iEdge];
1042  Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord;
1043  XCoord = Xcoord_Index1[iEdge]*cos(Angle) - Ycoord_Index1[iEdge]*sin(Angle);
1044  YCoord = Ycoord_Index1[iEdge]*cos(Angle) + Xcoord_Index1[iEdge]*sin(Angle);
1045  ZCoord = Zcoord_Index1[iEdge];
1046  Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord;
1047  }
1048  }
1049 
1050  /*--- Rotate nacelle secction to a X-Z plane to reuse the rest of subroutines ---*/
1051 
1052 
1053  if (config->GetGeo_Description() == NACELLE) {
1054 
1055  su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180;
1056  su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180;
1057  su2double Theta_deg = atan2(Plane_Normal[1],-Plane_Normal[2])/PI_NUMBER*180 + 180;
1058  su2double Roll_Angle = 0.5*PI_NUMBER - Theta_deg*PI_NUMBER/180;
1059 
1060  su2double XCoord_Trans, YCoord_Trans, ZCoord_Trans, XCoord_Trans_Tilt, YCoord_Trans_Tilt, ZCoord_Trans_Tilt,
1061  XCoord_Trans_Tilt_Toe, YCoord_Trans_Tilt_Toe, ZCoord_Trans_Tilt_Toe, XCoord, YCoord, ZCoord;
1062 
1063  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
1064 
1065  /*--- First point of the edge ---*/
1066 
1067  /*--- Translate to the origin ---*/
1068 
1069  XCoord_Trans = Xcoord_Index0[iEdge] - config->GetNacelleLocation(0);
1070  YCoord_Trans = Ycoord_Index0[iEdge] - config->GetNacelleLocation(1);
1071  ZCoord_Trans = Zcoord_Index0[iEdge] - config->GetNacelleLocation(2);
1072 
1073  /*--- Apply tilt angle ---*/
1074 
1075  XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle);
1076  YCoord_Trans_Tilt = YCoord_Trans;
1077  ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle);
1078 
1079  /*--- Apply toe angle ---*/
1080 
1081  XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle);
1082  YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle);
1083  ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt;
1084 
1085  /*--- Rotate to X-Z plane (roll) ---*/
1086 
1087  XCoord = XCoord_Trans_Tilt_Toe;
1088  YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle);
1089  ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle);
1090 
1091  /*--- Update coordinates ---*/
1092 
1093  Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord;
1094 
1095  /*--- Second point of the edge ---*/
1096 
1097  /*--- Translate to the origin ---*/
1098 
1099  XCoord_Trans = Xcoord_Index1[iEdge] - config->GetNacelleLocation(0);
1100  YCoord_Trans = Ycoord_Index1[iEdge] - config->GetNacelleLocation(1);
1101  ZCoord_Trans = Zcoord_Index1[iEdge] - config->GetNacelleLocation(2);
1102 
1103  /*--- Apply tilt angle ---*/
1104 
1105  XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle);
1106  YCoord_Trans_Tilt = YCoord_Trans;
1107  ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle);
1108 
1109  /*--- Apply toe angle ---*/
1110 
1111  XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle);
1112  YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle);
1113  ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt;
1114 
1115  /*--- Rotate to X-Z plane (roll) ---*/
1116 
1117  XCoord = XCoord_Trans_Tilt_Toe;
1118  YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle);
1119  ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle);
1120 
1121  /*--- Update coordinates ---*/
1122 
1123  Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord;
1124 
1125  }
1126  }
1127 
1128 
1129  /*--- Identify the extreme of the curve and close it ---*/
1130 
1131  Conection_Index0.reserve(Xcoord_Index0.size()+1);
1132  Conection_Index1.reserve(Xcoord_Index0.size()+1);
1133 
1134  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
1135  Conection_Index0[iEdge] = 0;
1136  Conection_Index1[iEdge] = 0;
1137  }
1138 
1139  for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) {
1140  for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) {
1141 
1142  if (((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) ||
1143  ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge])))
1144  { Conection_Index0[iEdge]++; Conection_Index0[jEdge]++; }
1145 
1146  if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) ||
1147  ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge])))
1148  { Conection_Index0[iEdge]++; Conection_Index1[jEdge]++; }
1149 
1150  if (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) ||
1151  ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge])))
1152  { Conection_Index1[iEdge]++; Conection_Index0[jEdge]++; }
1153 
1154  if (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) ||
1155  ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge])))
1156  { Conection_Index1[iEdge]++; Conection_Index1[jEdge]++; }
1157 
1158  }
1159  }
1160 
1161  /*--- Connect extremes of the curves ---*/
1162 
1163  /*--- First: Identify the extremes of the curve in the extra vector ---*/
1164 
1165  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
1166  if (Conection_Index0[iEdge] == 0) {
1167  XcoordExtra.push_back(Xcoord_Index0[iEdge]);
1168  YcoordExtra.push_back(Ycoord_Index0[iEdge]);
1169  ZcoordExtra.push_back(Zcoord_Index0[iEdge]);
1170  VariableExtra.push_back(Variable_Index0[iEdge]);
1171  IGlobalIDExtra.push_back(IGlobalID_Index0[iEdge]);
1172  JGlobalIDExtra.push_back(JGlobalID_Index0[iEdge]);
1173  AddExtra.push_back(true);
1174  }
1175  if (Conection_Index1[iEdge] == 0) {
1176  XcoordExtra.push_back(Xcoord_Index1[iEdge]);
1177  YcoordExtra.push_back(Ycoord_Index1[iEdge]);
1178  ZcoordExtra.push_back(Zcoord_Index1[iEdge]);
1179  VariableExtra.push_back(Variable_Index1[iEdge]);
1180  IGlobalIDExtra.push_back(IGlobalID_Index1[iEdge]);
1181  JGlobalIDExtra.push_back(JGlobalID_Index1[iEdge]);
1182  AddExtra.push_back(true);
1183  }
1184  }
1185 
1186  /*--- Second, if it is an open curve then find the closest point to an extreme to close it ---*/
1187 
1188  if (XcoordExtra.size() > 1) {
1189 
1190  for (iEdge = 0; iEdge < XcoordExtra.size()-1; iEdge++) {
1191 
1192  su2double MinDist = 1E6; FoundEdge = false; EdgeDonor = 0;
1193  for (jEdge = iEdge+1; jEdge < XcoordExtra.size(); jEdge++) {
1194  Dist_Value = sqrt(pow(SU2_TYPE::GetValue(XcoordExtra[iEdge])-SU2_TYPE::GetValue(XcoordExtra[jEdge]), 2.0));
1195  if ((Dist_Value < MinDist) && (AddExtra[iEdge]) && (AddExtra[jEdge])) {
1196  EdgeDonor = jEdge; FoundEdge = true;
1197  }
1198  }
1199 
1200  if (FoundEdge) {
1201 
1202  /*--- Add first point of the new edge ---*/
1203 
1204  Xcoord_Index0.push_back (XcoordExtra[iEdge]);
1205  Ycoord_Index0.push_back (YcoordExtra[iEdge]);
1206  Zcoord_Index0.push_back (ZcoordExtra[iEdge]);
1207  Variable_Index0.push_back (VariableExtra[iEdge]);
1208  IGlobalID_Index0.push_back (IGlobalIDExtra[iEdge]);
1209  JGlobalID_Index0.push_back (JGlobalIDExtra[iEdge]);
1210  AddExtra[iEdge] = false;
1211 
1212  /*--- Add second (closest) point of the new edge ---*/
1213 
1214  Xcoord_Index1.push_back (XcoordExtra[EdgeDonor]);
1215  Ycoord_Index1.push_back (YcoordExtra[EdgeDonor]);
1216  Zcoord_Index1.push_back (ZcoordExtra[EdgeDonor]);
1217  Variable_Index1.push_back (VariableExtra[EdgeDonor]);
1218  IGlobalID_Index1.push_back (IGlobalIDExtra[EdgeDonor]);
1219  JGlobalID_Index1.push_back (JGlobalIDExtra[EdgeDonor]);
1220  AddExtra[EdgeDonor] = false;
1221 
1222  }
1223 
1224  }
1225 
1226  }
1227 
1228  else if (XcoordExtra.size() == 1) {
1229  cout <<"There cutting system has failed, there is an incomplete curve (not used)." << endl;
1230  }
1231 
1232  /*--- Find and add the trailing edge to to the list
1233  and the contect the first point to the trailing edge ---*/
1234 
1235  Trailing_Point = 0; Trailing_Coord = Xcoord_Index0[0];
1236  for (iEdge = 1; iEdge < Xcoord_Index0.size(); iEdge++) {
1237  if (Xcoord_Index0[iEdge] > Trailing_Coord) {
1238  Trailing_Point = iEdge; Trailing_Coord = Xcoord_Index0[iEdge];
1239  }
1240  }
1241 
1242  Xcoord_Airfoil.push_back(Xcoord_Index0[Trailing_Point]);
1243  Ycoord_Airfoil.push_back(Ycoord_Index0[Trailing_Point]);
1244  Zcoord_Airfoil.push_back(Zcoord_Index0[Trailing_Point]);
1245  Variable_Airfoil.push_back(Variable_Index0[Trailing_Point]);
1246  IGlobalID_Airfoil.push_back(IGlobalID_Index0[Trailing_Point]);
1247  JGlobalID_Airfoil.push_back(JGlobalID_Index0[Trailing_Point]);
1248 
1249  Xcoord_Airfoil.push_back(Xcoord_Index1[Trailing_Point]);
1250  Ycoord_Airfoil.push_back(Ycoord_Index1[Trailing_Point]);
1251  Zcoord_Airfoil.push_back(Zcoord_Index1[Trailing_Point]);
1252  Variable_Airfoil.push_back(Variable_Index1[Trailing_Point]);
1253  IGlobalID_Airfoil.push_back(IGlobalID_Index1[Trailing_Point]);
1254  JGlobalID_Airfoil.push_back(JGlobalID_Index1[Trailing_Point]);
1255 
1256  Xcoord_Index0.erase (Xcoord_Index0.begin() + Trailing_Point);
1257  Ycoord_Index0.erase (Ycoord_Index0.begin() + Trailing_Point);
1258  Zcoord_Index0.erase (Zcoord_Index0.begin() + Trailing_Point);
1259  Variable_Index0.erase (Variable_Index0.begin() + Trailing_Point);
1260  IGlobalID_Index0.erase (IGlobalID_Index0.begin() + Trailing_Point);
1261  JGlobalID_Index0.erase (JGlobalID_Index0.begin() + Trailing_Point);
1262 
1263  Xcoord_Index1.erase (Xcoord_Index1.begin() + Trailing_Point);
1264  Ycoord_Index1.erase (Ycoord_Index1.begin() + Trailing_Point);
1265  Zcoord_Index1.erase (Zcoord_Index1.begin() + Trailing_Point);
1266  Variable_Index1.erase (Variable_Index1.begin() + Trailing_Point);
1267  IGlobalID_Index1.erase (IGlobalID_Index1.begin() + Trailing_Point);
1268  JGlobalID_Index1.erase (JGlobalID_Index1.begin() + Trailing_Point);
1269 
1270 
1271  /*--- Algorithm for adding the rest of the points ---*/
1272 
1273  do {
1274 
1275  /*--- Last added point in the list ---*/
1276 
1277  Airfoil_Point = Xcoord_Airfoil.size() - 1;
1278 
1279  /*--- Find the closest point ---*/
1280 
1281  Found_Edge = false;
1282 
1283  for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) {
1284 
1285  if (((IGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) ||
1286  ((IGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) {
1287  Next_Edge = iEdge; Found_Edge = true; Index = 0; break;
1288  }
1289 
1290  if (((IGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) ||
1291  ((IGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) {
1292  Next_Edge = iEdge; Found_Edge = true; Index = 1; break;
1293  }
1294 
1295  }
1296 
1297  /*--- Add and remove the next point to the list and the next point in the edge ---*/
1298 
1299  if (Found_Edge) {
1300 
1301  if (Index == 0) {
1302  Xcoord_Airfoil.push_back(Xcoord_Index1[Next_Edge]);
1303  Ycoord_Airfoil.push_back(Ycoord_Index1[Next_Edge]);
1304  Zcoord_Airfoil.push_back(Zcoord_Index1[Next_Edge]);
1305  Variable_Airfoil.push_back(Variable_Index1[Next_Edge]);
1306  IGlobalID_Airfoil.push_back(IGlobalID_Index1[Next_Edge]);
1307  JGlobalID_Airfoil.push_back(JGlobalID_Index1[Next_Edge]);
1308  }
1309 
1310  if (Index == 1) {
1311  Xcoord_Airfoil.push_back(Xcoord_Index0[Next_Edge]);
1312  Ycoord_Airfoil.push_back(Ycoord_Index0[Next_Edge]);
1313  Zcoord_Airfoil.push_back(Zcoord_Index0[Next_Edge]);
1314  Variable_Airfoil.push_back(Variable_Index0[Next_Edge]);
1315  IGlobalID_Airfoil.push_back(IGlobalID_Index0[Next_Edge]);
1316  JGlobalID_Airfoil.push_back(JGlobalID_Index0[Next_Edge]);
1317  }
1318 
1319  Xcoord_Index0.erase(Xcoord_Index0.begin() + Next_Edge);
1320  Ycoord_Index0.erase(Ycoord_Index0.begin() + Next_Edge);
1321  Zcoord_Index0.erase(Zcoord_Index0.begin() + Next_Edge);
1322  Variable_Index0.erase(Variable_Index0.begin() + Next_Edge);
1323  IGlobalID_Index0.erase(IGlobalID_Index0.begin() + Next_Edge);
1324  JGlobalID_Index0.erase(JGlobalID_Index0.begin() + Next_Edge);
1325 
1326  Xcoord_Index1.erase(Xcoord_Index1.begin() + Next_Edge);
1327  Ycoord_Index1.erase(Ycoord_Index1.begin() + Next_Edge);
1328  Zcoord_Index1.erase(Zcoord_Index1.begin() + Next_Edge);
1329  Variable_Index1.erase(Variable_Index1.begin() + Next_Edge);
1330  IGlobalID_Index1.erase(IGlobalID_Index1.begin() + Next_Edge);
1331  JGlobalID_Index1.erase(JGlobalID_Index1.begin() + Next_Edge);
1332 
1333  }
1334  else { break; }
1335 
1336  } while (Xcoord_Index0.size() != 0);
1337 
1338  /*--- Clean the vector before using them again for storing the upper or the lower side ---*/
1339 
1340  Xcoord_Index0.clear(); Ycoord_Index0.clear(); Zcoord_Index0.clear(); Variable_Index0.clear(); IGlobalID_Index0.clear(); JGlobalID_Index0.clear();
1341  Xcoord_Index1.clear(); Ycoord_Index1.clear(); Zcoord_Index1.clear(); Variable_Index1.clear(); IGlobalID_Index1.clear(); JGlobalID_Index1.clear();
1342 
1343  }
1344 
1345  }
1346 
1348 
1349 }
1350 
1352  unsigned short iDim;
1353  unsigned long iPoint;
1354 
1355  for (iPoint = 0; iPoint < nPoint; iPoint++) {
1356  for (iDim = 0; iDim < nDim; iDim++) {
1357  AD::RegisterInput(node[iPoint]->GetCoord()[iDim]);
1358  }
1359  }
1360 }
1361 
1363  unsigned short iDim;
1364  unsigned long iPoint;
1365 
1366  for (iPoint = 0; iPoint < nPoint; iPoint++){
1367  for (iDim = 0; iDim < nDim; iDim++){
1368  AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]);
1369  }
1370  }
1371 }
1372 
1373 void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config) {
1374 
1375  unsigned short iMesh;
1376  geometry_container[MESH_0]->Set_MPI_Coord(config);
1377  if (config->GetGrid_Movement()){
1378  geometry_container[MESH_0]->Set_MPI_GridVel(config);
1379  }
1380 
1381  geometry_container[MESH_0]->SetCoord_CG();
1382  geometry_container[MESH_0]->SetControlVolume(config, UPDATE);
1383  geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE);
1384  geometry_container[MESH_0]->SetMaxLength(config);
1385 
1386  for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) {
1387  /*--- Update the control volume structures ---*/
1388 
1389  geometry_container[iMesh]->SetControlVolume(config,geometry_container[iMesh-1], UPDATE);
1390  geometry_container[iMesh]->SetBoundControlVolume(config,geometry_container[iMesh-1], UPDATE);
1391  geometry_container[iMesh]->SetCoord(geometry_container[iMesh-1]);
1392 
1393  }
1394 
1395  if (config->GetKind_Solver() == DISC_ADJ_RANS)
1396  geometry_container[MESH_0]->ComputeWall_Distance(config);
1397 
1398 }
1399 
1401 
1402  unsigned short iMarker;
1403  unsigned long iVertex;
1404  string Marker_Tag;
1405 
1406  /* --- Initialize quantities for customized boundary conditions.
1407  * Custom values are initialized with the default values specified in the config (avoiding non physical values) --- */
1410 
1411  for(iMarker=0; iMarker < nMarker; iMarker++){
1412  Marker_Tag = config->GetMarker_All_TagBound(iMarker);
1413  CustomBoundaryHeatFlux[iMarker] = NULL;
1414  CustomBoundaryTemperature[iMarker] = NULL;
1415  if(config->GetMarker_All_PyCustom(iMarker)){
1416  switch(config->GetMarker_All_KindBC(iMarker)){
1417  case HEAT_FLUX:
1418  CustomBoundaryHeatFlux[iMarker] = new su2double[nVertex[iMarker]];
1419  for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){
1420  CustomBoundaryHeatFlux[iMarker][iVertex] = config->GetWall_HeatFlux(Marker_Tag);
1421  }
1422  break;
1423  case ISOTHERMAL:
1424  CustomBoundaryTemperature[iMarker] = new su2double[nVertex[iMarker]];
1425  for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){
1426  CustomBoundaryTemperature[iMarker][iVertex] = config->GetIsothermal_Temperature(Marker_Tag);
1427  }
1428  break;
1429  case INLET_FLOW:
1430  // This case is handled in the solver class.
1431  break;
1432  default:
1433  cout << "WARNING: Marker " << Marker_Tag << " is not customizable. Using default behavior." << endl;
1434  break;
1435  }
1436  }
1437  }
1438 
1439 }
1440 
1442 
1443  unsigned short iMGfine, iMGlevel, nMGlevel, iMarker;
1444 
1445  nMGlevel = config->GetnMGLevels();
1446  for (iMGlevel=1; iMGlevel <= nMGlevel; iMGlevel++){
1447  iMGfine = iMGlevel-1;
1448  for(iMarker = 0; iMarker< config->GetnMarker_All(); iMarker++){
1449  if(config->GetMarker_All_PyCustom(iMarker)){
1450  switch(config->GetMarker_All_KindBC(iMarker)){
1451  case HEAT_FLUX:
1452  geometry_container[iMGlevel]->SetMultiGridWallHeatFlux(geometry_container[iMGfine], iMarker);
1453  break;
1454  case ISOTHERMAL:
1455  geometry_container[iMGlevel]->SetMultiGridWallTemperature(geometry_container[iMGfine], iMarker);
1456  break;
1457  // Inlet flow handled in solver class.
1458  default: break;
1459  }
1460  }
1461  }
1462  }
1463 }
1464 
1466  unsigned short iMarker, iNeigh_Point, iDim, iNode, iNeighbor_Nodes, Neighbor_Node;
1467  unsigned long Neighbor_Point, iVertex, iPoint, jPoint, iElem_Bound, iEdge, nLocalVertex, MaxLocalVertex , *Buffer_Send_nVertex, *Buffer_Receive_nVertex, TotalnPointDomain;
1468  int iProcessor, nProcessor;
1469  vector<unsigned long> Point_NeighborList, Elem_NeighborList, Point_Triangle, Point_Edge, Point_Critical;
1470  vector<unsigned long>::iterator it;
1471  su2double U[3] = {0.0,0.0,0.0}, V[3] = {0.0,0.0,0.0}, W[3] = {0.0,0.0,0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK;
1472  bool *Check_Edge;
1473 
1474  bool fea = ((config->GetKind_Solver()==FEM_ELASTICITY) || (config->GetKind_Solver()==DISC_ADJ_FEM));
1475 
1476  /*--- Allocate surface curvature ---*/
1477  K = new su2double [nPoint];
1478  for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0;
1479 
1480  if (nDim == 2) {
1481 
1482  /*--- Loop over all the markers ---*/
1483  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1484 
1485  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1486 
1487  /*--- Loop through all marker vertices again, this time also
1488  finding the neighbors of each node.---*/
1489  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
1490  iPoint = vertex[iMarker][iVertex]->GetNode();
1491 
1492  if (node[iPoint]->GetDomain()) {
1493  /*--- Loop through neighbors. In 2-D, there should be 2 nodes on either
1494  side of this vertex that lie on the same surface. ---*/
1495  Point_Edge.clear();
1496 
1497  for (iNeigh_Point = 0; iNeigh_Point < node[iPoint]->GetnPoint(); iNeigh_Point++) {
1498  Neighbor_Point = node[iPoint]->GetPoint(iNeigh_Point);
1499 
1500  /*--- Check if this neighbor lies on the surface. If so,
1501  add to the list of neighbors. ---*/
1502  if (node[Neighbor_Point]->GetPhysicalBoundary()) {
1503  Point_Edge.push_back(Neighbor_Point);
1504  }
1505 
1506  }
1507 
1508  if (Point_Edge.size() == 2) {
1509 
1510  /*--- Compute the curvature using three points ---*/
1511  X1 = node[iPoint]->GetCoord(0);
1512  X2 = node[Point_Edge[0]]->GetCoord(0);
1513  X3 = node[Point_Edge[1]]->GetCoord(0);
1514  Y1 = node[iPoint]->GetCoord(1);
1515  Y2 = node[Point_Edge[0]]->GetCoord(1);
1516  Y3 = node[Point_Edge[1]]->GetCoord(1);
1517 
1518  radius = sqrt(((X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1))*
1519  ((X2-X3)*(X2-X3) + (Y2-Y3)*(Y2-Y3))*
1520  ((X3-X1)*(X3-X1) + (Y3-Y1)*(Y3-Y1)))/
1521  (2.0*fabs(X1*Y2+X2*Y3+X3*Y1-X1*Y3-X2*Y1-X3*Y2)+EPS);
1522 
1523  K[iPoint] = 1.0/radius;
1524  node[iPoint]->SetCurvature(K[iPoint]);
1525  }
1526 
1527  }
1528 
1529  }
1530 
1531  }
1532 
1533  }
1534 
1535  }
1536 
1537  else {
1538 
1539  Angle_Defect = new su2double [nPoint];
1540  Area_Vertex = new su2double [nPoint];
1541  for (iPoint = 0; iPoint < nPoint; iPoint++) {
1542  Angle_Defect[iPoint] = 2*PI_NUMBER;
1543  Area_Vertex[iPoint] = 0.0;
1544  }
1545 
1546  Angle_Alpha = new su2double [nEdge];
1547  Angle_Beta = new su2double [nEdge];
1548  Check_Edge = new bool [nEdge];
1549  for (iEdge = 0; iEdge < nEdge; iEdge++) {
1550  Angle_Alpha[iEdge] = 0.0;
1551  Angle_Beta[iEdge] = 0.0;
1552  Check_Edge[iEdge] = true;
1553  }
1554 
1555  NormalMeanK = new su2double *[nPoint];
1556  for (iPoint = 0; iPoint < nPoint; iPoint++) {
1557  NormalMeanK[iPoint] = new su2double [nDim];
1558  for (iDim = 0; iDim < nDim; iDim++) {
1559  NormalMeanK[iPoint][iDim] = 0.0;
1560  }
1561  }
1562 
1563  /*--- Loop over all the markers ---*/
1564  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1565 
1566  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1567 
1568  /*--- Loop over all the boundary elements ---*/
1569  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
1570 
1571  /*--- Only triangles ---*/
1572  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) {
1573 
1574  /*--- Loop over all the nodes of the boundary element ---*/
1575  for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) {
1576 
1577  iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode);
1578 
1579  Point_Triangle.clear();
1580 
1581  for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) {
1582  Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes);
1583  Neighbor_Point = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node);
1584  Point_Triangle.push_back(Neighbor_Point);
1585  }
1586 
1587  iEdge = FindEdge(Point_Triangle[0], Point_Triangle[1]);
1588 
1589  for (iDim = 0; iDim < nDim; iDim++) {
1590  U[iDim] = node[Point_Triangle[0]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim);
1591  V[iDim] = node[Point_Triangle[1]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim);
1592  }
1593 
1594  W[0] = 0.5*(U[1]*V[2]-U[2]*V[1]); W[1] = -0.5*(U[0]*V[2]-U[2]*V[0]); W[2] = 0.5*(U[0]*V[1]-U[1]*V[0]);
1595 
1596  Length_U = 0.0; Length_V = 0.0; Length_W = 0.0; CosValue = 0.0;
1597  for (iDim = 0; iDim < nDim; iDim++) { Length_U += U[iDim]*U[iDim]; Length_V += V[iDim]*V[iDim]; Length_W += W[iDim]*W[iDim]; }
1598  Length_U = sqrt(Length_U); Length_V = sqrt(Length_V); Length_W = sqrt(Length_W);
1599  for (iDim = 0; iDim < nDim; iDim++) { U[iDim] /= Length_U; V[iDim] /= Length_V; CosValue += U[iDim]*V[iDim]; }
1600  if (CosValue >= 1.0) CosValue = 1.0;
1601  if (CosValue <= -1.0) CosValue = -1.0;
1602 
1603  Angle_Value = acos(CosValue);
1604  Area_Vertex[iPoint] += Length_W;
1605  Angle_Defect[iPoint] -= Angle_Value;
1606  if (Angle_Alpha[iEdge] == 0.0) Angle_Alpha[iEdge] = Angle_Value;
1607  else Angle_Beta[iEdge] = Angle_Value;
1608 
1609  }
1610  }
1611  }
1612  }
1613  }
1614 
1615  /*--- Compute mean curvature ---*/
1616  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1617  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1618  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
1619  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) {
1620  for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) {
1621  iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode);
1622 
1623  for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) {
1624  Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes);
1625  jPoint = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node);
1626 
1627  iEdge = FindEdge(iPoint, jPoint);
1628 
1629  if (Check_Edge[iEdge]) {
1630 
1631  Check_Edge[iEdge] = false;
1632 
1633  if (tan(Angle_Alpha[iEdge]) != 0.0) cot_alpha = 1.0/tan(Angle_Alpha[iEdge]); else cot_alpha = 0.0;
1634  if (tan(Angle_Beta[iEdge]) != 0.0) cot_beta = 1.0/tan(Angle_Beta[iEdge]); else cot_beta = 0.0;
1635 
1636  /*--- iPoint, and jPoint ---*/
1637  for (iDim = 0; iDim < nDim; iDim++) {
1638  if (Area_Vertex[iPoint] != 0.0) NormalMeanK[iPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[iPoint]->GetCoord(iDim) - node[jPoint]->GetCoord(iDim)) / Area_Vertex[iPoint];
1639  if (Area_Vertex[jPoint] != 0.0) NormalMeanK[jPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[jPoint]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim)) / Area_Vertex[jPoint];
1640  }
1641  }
1642 
1643  }
1644  }
1645  }
1646  }
1647  }
1648  }
1649 
1650  /*--- Compute Gauss, mean, max and min principal curvature,
1651  and set the list of critical points ---*/
1652 
1653  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1654  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1655  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
1656  iPoint = vertex[iMarker][iVertex]->GetNode();
1657 
1658  if (node[iPoint]->GetDomain()) {
1659 
1660  if (Area_Vertex[iPoint] != 0.0) GaussK = 3.0*Angle_Defect[iPoint]/Area_Vertex[iPoint];
1661  else GaussK = 0.0;
1662 
1663  MeanK = 0.0;
1664  for (iDim = 0; iDim < nDim; iDim++)
1665  MeanK += NormalMeanK[iPoint][iDim]*NormalMeanK[iPoint][iDim];
1666  MeanK = sqrt(MeanK);
1667 
1668  delta = max((MeanK*MeanK - GaussK), 0.0);
1669 
1670  MaxPrinK = MeanK + sqrt(delta);
1671 
1672  /*--- Store the curvature value ---*/
1673  K[iPoint] = MaxPrinK;
1674  node[iPoint]->SetCurvature(K[iPoint]);
1675  }
1676 
1677  }
1678  }
1679  }
1680 
1681  delete [] Angle_Defect;
1682  delete [] Area_Vertex;
1683  delete [] Angle_Alpha;
1684  delete [] Angle_Beta;
1685  delete [] Check_Edge;
1686 
1687  for (iPoint = 0; iPoint < nPoint; iPoint++)
1688  delete [] NormalMeanK[iPoint];
1689  delete [] NormalMeanK;
1690 
1691  }
1692 
1693  /*--- Sharp edge detection is based in the statistical
1694  distribution of the curvature ---*/
1695 
1696  MaxK = K[0]; MinK = K[0]; MeanK = 0.0; TotalnPointDomain = 0;
1697  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1698  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1699  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
1700  iPoint = vertex[iMarker][iVertex]->GetNode();
1701  if (node[iPoint]->GetDomain()) {
1702  MaxK = max(MaxK, fabs(K[iPoint]));
1703  MinK = min(MinK, fabs(K[iPoint]));
1704  MeanK += fabs(K[iPoint]);
1705  TotalnPointDomain++;
1706  }
1707  }
1708  }
1709  }
1710 
1711 #ifdef HAVE_MPI
1712  su2double MyMeanK = MeanK; MeanK = 0.0;
1713  su2double MyMaxK = MaxK; MaxK = 0.0;
1714  unsigned long MynPointDomain = TotalnPointDomain; TotalnPointDomain = 0;
1715  SU2_MPI::Allreduce(&MyMeanK, &MeanK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
1716  SU2_MPI::Allreduce(&MyMaxK, &MaxK, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
1717  SU2_MPI::Allreduce(&MynPointDomain, &TotalnPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
1718 #endif
1719 
1720  /*--- Compute the mean ---*/
1721  MeanK /= su2double(TotalnPointDomain);
1722 
1723  /*--- Compute the standard deviation ---*/
1724  SigmaK = 0.0;
1725  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1726  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1727  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
1728  iPoint = vertex[iMarker][iVertex]->GetNode();
1729  if (node[iPoint]->GetDomain()) {
1730  SigmaK += (fabs(K[iPoint]) - MeanK) * (fabs(K[iPoint]) - MeanK);
1731  }
1732  }
1733  }
1734  }
1735 
1736 #ifdef HAVE_MPI
1737  su2double MySigmaK = SigmaK; SigmaK = 0.0;
1738  SU2_MPI::Allreduce(&MySigmaK, &SigmaK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
1739 #endif
1740 
1741  SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain));
1742 
1743  if ((rank == MASTER_NODE) && (!fea))
1744  cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl;
1745 
1746  Point_Critical.clear();
1747 
1748  for (iMarker = 0; iMarker < nMarker; iMarker++) {
1749  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
1750  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
1751  iPoint = vertex[iMarker][iVertex]->GetNode();
1752  if (node[iPoint]->GetDomain()) {
1753  if (fabs(K[iPoint]) > MeanK + config->GetRefSharpEdges()*SigmaK) {
1754  Point_Critical.push_back(iPoint);
1755  }
1756  }
1757  }
1758  }
1759  }
1760 
1761  /*--- Variables and buffers needed for MPI ---*/
1762 
1763 #ifdef HAVE_MPI
1764  SU2_MPI::Comm_size(MPI_COMM_WORLD, &nProcessor);
1765 #else
1766  nProcessor = 1;
1767 #endif
1768 
1769  Buffer_Send_nVertex = new unsigned long [1];
1770  Buffer_Receive_nVertex = new unsigned long [nProcessor];
1771 
1772  /*--- Count the total number of critical edge nodes. ---*/
1773 
1774  nLocalVertex = Point_Critical.size();
1775  Buffer_Send_nVertex[0] = nLocalVertex;
1776 
1777  /*--- Communicate to all processors the total number of critical edge nodes. ---*/
1778 
1779 #ifdef HAVE_MPI
1780  MaxLocalVertex = 0;
1781  SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
1782  SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
1783 #else
1784  MaxLocalVertex = nLocalVertex;
1785  Buffer_Receive_nVertex[0] = nLocalVertex;
1786 #endif
1787 
1788 
1789  /*--- Create and initialize to zero some buffers to hold the coordinates
1790  of the boundary nodes that are communicated from each partition (all-to-all). ---*/
1791 
1792  Buffer_Send_Coord = new su2double [MaxLocalVertex*nDim];
1793  Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*nDim];
1794 
1795 #ifdef HAVE_MPI
1796  unsigned long nBuffer = MaxLocalVertex*nDim;
1797 #endif
1798 
1799  for (iVertex = 0; iVertex < MaxLocalVertex; iVertex++) {
1800  for (iDim = 0; iDim < nDim; iDim++) {
1801  Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0;
1802  }
1803  }
1804 
1805  /*--- Retrieve and store the coordinates of the sharp edges boundary nodes on
1806  the local partition and broadcast them to all partitions. ---*/
1807 
1808  for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) {
1809  iPoint = Point_Critical[iVertex];
1810  for (iDim = 0; iDim < nDim; iDim++)
1811  Buffer_Send_Coord[iVertex*nDim+iDim] = node[iPoint]->GetCoord(iDim);
1812  }
1813 
1814 #ifdef HAVE_MPI
1815  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD);
1816 #else
1817  for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) {
1818  for (iDim = 0; iDim < nDim; iDim++) {
1819  Buffer_Receive_Coord[iVertex*nDim+iDim] = Buffer_Send_Coord[iVertex*nDim+iDim];
1820  }
1821  }
1822 #endif
1823 
1824  /*--- Loop over all interior mesh nodes on the local partition and compute
1825  the distances to each of the no-slip boundary nodes in the entire mesh.
1826  Store the minimum distance to the wall for each interior mesh node. ---*/
1827 
1828  for (iPoint = 0; iPoint < GetnPoint(); iPoint++) {
1829  Coord = node[iPoint]->GetCoord();
1830 
1831  MinDist = 1E20;
1832  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) {
1833  for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) {
1834  Dist = 0.0;
1835  for (iDim = 0; iDim < nDim; iDim++) {
1836  Dist += (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim])*
1837  (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim]);
1838  }
1839  if (Dist!=0.0) Dist = sqrt(Dist);
1840  else Dist = 0.0;
1841  if (Dist < MinDist) MinDist = Dist;
1842  }
1843  }
1844  node[iPoint]->SetSharpEdge_Distance(MinDist);
1845  }
1846 
1847  /*--- Deallocate Max curvature ---*/
1848  delete[] K;
1849 
1850  /*--- Deallocate the buffers needed for the MPI communication. ---*/
1851  delete[] Buffer_Send_Coord;
1852  delete[] Buffer_Receive_Coord;
1853  delete[] Buffer_Send_nVertex;
1854  delete[] Buffer_Receive_nVertex;
1855 
1856 }
1857 
1859 
1860  size = SU2_MPI::GetSize();
1861  rank = SU2_MPI::GetRank();
1862 
1863  Local_to_Global_Point = NULL;
1864  Local_to_Global_Marker = NULL;
1865  Global_to_Local_Marker = NULL;
1866 
1867  starting_node = NULL;
1868  ending_node = NULL;
1869  npoint_procs = NULL;
1870  nPoint_Linear = NULL;
1871 
1872  /*--- Arrays for defining the turbomachinery structure ---*/
1873 
1874  nSpanWiseSections = NULL;
1875  nSpanSectionsByMarker = NULL;
1876  SpanWiseValue = NULL;
1877  nVertexSpan = NULL;
1878  nTotVertexSpan = NULL;
1879  turbovertex = NULL;
1880  AverageTurboNormal = NULL;
1881  AverageNormal = NULL;
1882  AverageGridVel = NULL;
1883  AverageTangGridVel = NULL;
1884  SpanArea = NULL;
1885  TurboRadius = NULL;
1886  MaxAngularCoord = NULL;
1887  MinAngularCoord = NULL;
1888  MinRelAngularCoord = NULL;
1889 
1890  TangGridVelIn = NULL;
1891  SpanAreaIn = NULL;
1892  TurboRadiusIn = NULL;
1893  TangGridVelOut = NULL;
1894  SpanAreaOut = NULL;
1895  TurboRadiusOut = NULL;
1896 
1897 }
1898 
1899 CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone) : CGeometry() {
1900 
1901  size = SU2_MPI::GetSize();
1902  rank = SU2_MPI::GetRank();
1903 
1904  Local_to_Global_Point = NULL;
1905  Local_to_Global_Marker = NULL;
1906  Global_to_Local_Marker = NULL;
1907 
1908  starting_node = NULL;
1909  ending_node = NULL;
1910  npoint_procs = NULL;
1911  nPoint_Linear = NULL;
1912 
1913  /*--- Arrays for defining the turbomachinery structure ---*/
1914 
1915  nSpanWiseSections = NULL;
1916  nSpanSectionsByMarker = NULL;
1917  SpanWiseValue = NULL;
1918  nVertexSpan = NULL;
1919  nTotVertexSpan = NULL;
1920  turbovertex = NULL;
1921  AverageTurboNormal = NULL;
1922  AverageNormal = NULL;
1923  AverageGridVel = NULL;
1924  AverageTangGridVel = NULL;
1925  SpanArea = NULL;
1926  TurboRadius = NULL;
1927  MaxAngularCoord = NULL;
1928  MinAngularCoord = NULL;
1929  MinRelAngularCoord = NULL;
1930 
1931  TangGridVelIn = NULL;
1932  SpanAreaIn = NULL;
1933  TurboRadiusIn = NULL;
1934  TangGridVelOut = NULL;
1935  SpanAreaOut = NULL;
1936  TurboRadiusOut = NULL;
1937 
1938  string text_line, Marker_Tag;
1939  ifstream mesh_file;
1940  unsigned short iDim, iMarker, iNodes;
1941  unsigned long iPoint, iElem_Bound;
1942  su2double *NewCoord;
1943  nZone = val_nZone;
1944  ofstream boundary_file;
1945  string Grid_Marker;
1946 
1947  string val_mesh_filename = config->GetMesh_FileName();
1948  unsigned short val_format = config->GetMesh_FileFormat();
1949 
1950  /*--- Determine whether or not a FEM discretization is used ---*/
1951 
1952  const bool fem_solver = ((config->GetKind_Solver() == FEM_EULER) ||
1953  (config->GetKind_Solver() == FEM_NAVIER_STOKES) ||
1954  (config->GetKind_Solver() == FEM_RANS) ||
1955  (config->GetKind_Solver() == FEM_LES) ||
1956  (config->GetKind_Solver() == DISC_ADJ_FEM_EULER) ||
1957  (config->GetKind_Solver() == DISC_ADJ_FEM_NS) ||
1958  (config->GetKind_Solver() == DISC_ADJ_FEM_RANS));
1959 
1960  /*--- Initialize counters for local/global points & elements ---*/
1961 
1962  if (rank == MASTER_NODE)
1963  cout << endl <<"---------------------- Read Grid File Information -----------------------" << endl;
1964 
1965  if( fem_solver ) {
1966  switch (val_format) {
1967  case SU2:
1968  Read_SU2_Format_Parallel_FEM(config, val_mesh_filename, val_iZone, val_nZone);
1969  break;
1970 
1971  case CGNS:
1972  Read_CGNS_Format_Parallel_FEM(config, val_mesh_filename, val_iZone, val_nZone);
1973  break;
1974 
1975  default:
1976  SU2_MPI::Error("Unrecognized mesh format specified for the FEM solver!", CURRENT_FUNCTION);
1977  break;
1978  }
1979  }
1980  else {
1981 
1982  switch (val_format) {
1983  case SU2:
1984  Read_SU2_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone);
1985  break;
1986  case CGNS:
1987  Read_CGNS_Format_Parallel(config, val_mesh_filename, val_iZone, val_nZone);
1988  break;
1989  default:
1990  SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION);
1991  break;
1992  }
1993  }
1994 
1995  /*--- After reading the mesh, assert that the dimension is equal to 2 or 3. ---*/
1996 
1997  assert((nDim == 2) || (nDim == 3));
1998 
1999  /*--- Loop over the points element to re-scale the mesh, and plot it (only SU2_CFD) ---*/
2000 
2001  if (config->GetKind_SU2() == SU2_CFD) {
2002 
2003  NewCoord = new su2double [nDim];
2004 
2005  /*--- The US system uses feet, but SU2 assumes that the grid is in inches ---*/
2006 
2007  if (config->GetSystemMeasurements() == US) {
2008  for (iPoint = 0; iPoint < nPoint; iPoint++) {
2009  for (iDim = 0; iDim < nDim; iDim++) {
2010  NewCoord[iDim] = node[iPoint]->GetCoord(iDim)/12.0;
2011  }
2012  node[iPoint]->SetCoord(NewCoord);
2013  }
2014  }
2015 
2016  delete [] NewCoord;
2017 
2018  }
2019 
2020  /*--- If SU2_DEF then write a file with the boundary information ---*/
2021 
2022  if ((config->GetKind_SU2() == SU2_DEF) && (rank == MASTER_NODE)) {
2023 
2024  string str = "boundary.dat";
2025 
2026  str = config->GetMultizone_FileName(str, val_iZone);
2027 
2028  /*--- Open .su2 grid file ---*/
2029 
2030  boundary_file.open(str.c_str(), ios::out);
2031 
2032  /*--- Loop through and write the boundary info ---*/
2033 
2034  boundary_file << "NMARK= " << nMarker << endl;
2035 
2036  for (iMarker = 0; iMarker < nMarker; iMarker++) {
2037 
2038  Grid_Marker = config->GetMarker_All_TagBound(iMarker);
2039  boundary_file << "MARKER_TAG= " << Grid_Marker << endl;
2040  boundary_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl;
2041  boundary_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl;
2042  if (nDim == 2) {
2043  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
2044  boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
2045  for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++)
2046  boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ;
2047 
2048  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == VERTEX) {
2049  boundary_file << bound[iMarker][iElem_Bound]->GetRotation_Type() << "\t";
2050  }
2051  boundary_file << iElem_Bound << endl;
2052  }
2053  }
2054 
2055  if (nDim == 3) {
2056  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
2057  boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
2058  for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++)
2059  boundary_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ;
2060 
2061  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == VERTEX) {
2062  boundary_file << bound[iMarker][iElem_Bound]->GetRotation_Type() << "\t";
2063  }
2064  boundary_file << iElem_Bound << endl;
2065  }
2066  }
2067 
2068  }
2069 
2070  boundary_file.close();
2071 
2072  }
2073 
2074 }
2075 
2077 
2078  /*--- Initialize several class data members for later. ---*/
2079 
2080  Local_to_Global_Point = NULL;
2081  Local_to_Global_Marker = NULL;
2082  Global_to_Local_Marker = NULL;
2083 
2084  starting_node = NULL;
2085  ending_node = NULL;
2086  npoint_procs = NULL;
2087  nPoint_Linear = NULL;
2088 
2089  /*--- Arrays for defining the turbomachinery structure ---*/
2090 
2091  nSpanWiseSections = NULL;
2092  nSpanSectionsByMarker = NULL;
2093  SpanWiseValue = NULL;
2094  nVertexSpan = NULL;
2095  nTotVertexSpan = NULL;
2096  turbovertex = NULL;
2097  AverageTurboNormal = NULL;
2098  AverageNormal = NULL;
2099  AverageGridVel = NULL;
2100  AverageTangGridVel = NULL;
2101  SpanArea = NULL;
2102  TurboRadius = NULL;
2103  MaxAngularCoord = NULL;
2104  MinAngularCoord = NULL;
2105  MinRelAngularCoord = NULL;
2106 
2107  TangGridVelIn = NULL;
2108  SpanAreaIn = NULL;
2109  TurboRadiusIn = NULL;
2110  TangGridVelOut = NULL;
2111  SpanAreaOut = NULL;
2112  TurboRadiusOut = NULL;
2113 
2114  /*--- Local variables and counters for the following communications. ---*/
2115 
2116  unsigned long iter, iPoint, jPoint, iElem, iVertex;
2117  unsigned long iElemTotal, iPointTotal, iPointGhost, iPointDomain, iPointPeriodic, iElemTriangle, iElemQuadrilateral, iElemTetrahedron, iElemHexahedron, iElemPrism, iElemPyramid, iPointCurrent;
2118  unsigned long nBoundLineTotal = 0, iBoundLineTotal;
2119  unsigned long nBoundTriangleTotal = 0, iBoundTriangleTotal;
2120  unsigned long nBoundQuadrilateralTotal = 0, iBoundQuadrilateralTotal;
2121  unsigned long ReceptorColor = 0, DonorColor = 0, Transformation;
2122  unsigned long nTotalSendDomain_Periodic = 0, iTotalSendDomain_Periodic, nTotalReceivedDomain_Periodic = 0, iTotalReceivedDomain_Periodic, *nSendDomain_Periodic = NULL, *nReceivedDomain_Periodic = NULL;
2123  unsigned long Buffer_Send_nPointTotal = 0, Buffer_Send_nPointDomainTotal = 0, Buffer_Send_nPointGhost = 0, Buffer_Send_nPointPeriodic = 0;
2124  unsigned long Buffer_Send_nElemTotal, Buffer_Send_nElemTriangle = 0, Buffer_Send_nElemQuadrilateral = 0, Buffer_Send_nElemTetrahedron = 0, Buffer_Send_nElemHexahedron = 0, Buffer_Send_nElemPrism = 0, Buffer_Send_nElemPyramid = 0;
2125  unsigned long Buffer_Send_nTotalSendDomain_Periodic = 0, Buffer_Send_nTotalReceivedDomain_Periodic = 0, *Buffer_Send_nSendDomain_Periodic = NULL, *Buffer_Send_nReceivedDomain_Periodic = NULL;
2126  unsigned long Buffer_Send_nBoundLineTotal = 0, Buffer_Send_nBoundTriangleTotal = 0, Buffer_Send_nBoundQuadrilateralTotal = 0;
2127  unsigned long iVertexDomain, iBoundLine, iBoundTriangle, iBoundQuadrilateral;
2128 
2129  unsigned long iNode, iDim, iMarker, jMarker, nMarkerDomain = 0, iMarkerDomain;
2130  unsigned long nDomain = 0, iDomain, jDomain, nPeriodic = 0, iPeriodic, Buffer_Send_nMarkerDomain = 0, Buffer_Send_nDim = 0, Buffer_Send_nZone = 0, Buffer_Send_nPeriodic = 0;
2131 
2132  bool *MarkerIn = NULL, **VertexIn = NULL, *ElemIn = NULL;
2133  long vnodes_local[8];
2134 
2135  vector<long> DomainList;
2136  short *Marker_All_SendRecv_Copy = NULL;
2137  string *Marker_All_TagBound_Copy = NULL;
2138 
2139  rank = SU2_MPI::GetRank();
2140  size = SU2_MPI::GetSize();
2141  unsigned short nMarker_Max = config->GetnMarker_Max();
2142 
2143 
2144  /*--- Some dynamic arrays so we're not allocating too much on the stack ---*/
2145 
2146  unsigned long *nVertexDomain = new unsigned long[nMarker_Max];
2147  unsigned long *nBoundLine = new unsigned long[nMarker_Max];
2148  unsigned long *nBoundTriangle = new unsigned long[nMarker_Max];
2149  unsigned long *nBoundQuadrilateral = new unsigned long[nMarker_Max];
2150 
2151  unsigned long *Buffer_Send_nVertexDomain = new unsigned long[nMarker_Max];
2152  unsigned long *Buffer_Send_nBoundLine = new unsigned long[nMarker_Max];
2153  unsigned long *Buffer_Send_nBoundTriangle = new unsigned long[nMarker_Max];
2154  unsigned long *Buffer_Send_nBoundQuadrilateral = new unsigned long[nMarker_Max];
2155 
2156  short *Buffer_Send_Marker_All_SendRecv = new short[nMarker_Max];
2157 
2158  char *Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE];
2159  char *Buffer_Send_Marker_All_TagBound = new char[nMarker_Max*MAX_STRING_SIZE];
2160 
2161 #ifdef HAVE_MPI
2162 
2163  /*--- MPI status and request arrays for non-blocking communications ---*/
2164 
2165  SU2_MPI::Status status, status2;
2166  unsigned long source;
2167  int recv_count=0;
2168 
2169  int offset = 17;
2170  SU2_MPI::Status *send_stat = new SU2_MPI::Status[offset+size];
2171  SU2_MPI::Status *recv_stat = new SU2_MPI::Status[offset+size];
2172 
2173  SU2_MPI::Request *send_req = new SU2_MPI::Request[offset+size];
2174  SU2_MPI::Request *recv_req = new SU2_MPI::Request[offset+size];
2175 
2176 #endif
2177 
2178  if (rank == MASTER_NODE && size > SINGLE_NODE)
2179  cout << "Communicating partition data and creating halo layers." << endl;
2180 
2181  /*--- Define buffer vectors for the interior points / elements ---*/
2182 
2183  su2double *Buffer_Send_Coord = NULL;
2184 
2185  unsigned long *Buffer_Send_Color = NULL;
2186  unsigned long *Buffer_Send_GlobalPointIndex = NULL;
2187  unsigned long *Buffer_Send_Triangle = NULL;
2188  unsigned long *Buffer_Send_Quadrilateral = NULL;
2189  unsigned long *Buffer_Send_Tetrahedron = NULL;
2190  unsigned long *Buffer_Send_Hexahedron = NULL;
2191  unsigned long *Buffer_Send_Prism = NULL;
2192  unsigned long *Buffer_Send_Pyramid = NULL;
2193  unsigned long *Buffer_Send_GlobElem = NULL;
2194 
2195  /*--- Define buffer vectors for boundary information ---*/
2196 
2197  unsigned long *Buffer_Send_BoundLine = NULL, *Buffer_Receive_BoundLine = NULL;
2198  unsigned long *Buffer_Send_BoundTriangle = NULL, *Buffer_Receive_BoundTriangle = NULL;
2199  unsigned long *Buffer_Send_BoundQuadrilateral = NULL, *Buffer_Receive_BoundQuadrilateral = NULL;
2200  unsigned long *Buffer_Send_Local2Global_Marker = NULL, *Buffer_Receive_Local2Global_Marker = NULL;
2201 
2202  /*--- Define buffer vectors for periodic boundary conditions ---*/
2203 
2204  su2double *Buffer_Send_Center = NULL, *Buffer_Receive_Center = NULL;
2205  su2double *Buffer_Send_Rotation = NULL, *Buffer_Receive_Rotation = NULL;
2206  su2double *Buffer_Send_Translate = NULL, *Buffer_Receive_Translate = NULL;
2207 
2208  /*--- Define buffer vector periodic boundary conditions ---*/
2209 
2210  unsigned long *Buffer_Send_SendDomain_Periodic = NULL, *Buffer_Receive_SendDomain_Periodic = NULL;
2211  unsigned long *Buffer_Send_SendDomain_PeriodicTrans = NULL, *Buffer_Receive_SendDomain_PeriodicTrans = NULL;
2212  unsigned long *Buffer_Send_SendDomain_PeriodicReceptor = NULL, *Buffer_Receive_SendDomain_PeriodicReceptor = NULL;
2213  unsigned long *Buffer_Send_ReceivedDomain_Periodic = NULL, *Buffer_Receive_ReceivedDomain_Periodic = NULL;
2214  unsigned long *Buffer_Send_ReceivedDomain_PeriodicTrans = NULL, *Buffer_Receive_ReceivedDomain_PeriodicTrans = NULL;
2215  unsigned long *Buffer_Send_ReceivedDomain_PeriodicDonor = NULL, *Buffer_Receive_ReceivedDomain_PeriodicDonor = NULL;
2216 
2217  /*--- Variables below are needed specifically for the ParMETIS version ---*/
2218 
2219  unsigned short *nDim_s = new unsigned short[size];
2220  unsigned short *nDim_r = new unsigned short[size];
2221  unsigned short *nZone_s = new unsigned short[size];
2222  unsigned short *nZone_r = new unsigned short[size];
2223 
2224  unsigned long *nPointTotal_s = new unsigned long[size];
2225  unsigned long *nPointDomainTotal_s = new unsigned long[size];
2226  unsigned long *nPointGhost_s = new unsigned long[size];
2227  unsigned long *nPointPeriodic_s = new unsigned long[size];
2228  unsigned long *nElemTotal_s = new unsigned long[size];
2229  unsigned long *nElemTriangle_s = new unsigned long[size];
2230  unsigned long *nElemQuadrilateral_s = new unsigned long[size];
2231  unsigned long *nElemTetrahedron_s = new unsigned long[size];
2232  unsigned long *nElemHexahedron_s = new unsigned long[size];
2233  unsigned long *nElemPrism_s = new unsigned long[size];
2234  unsigned long *nElemPyramid_s = new unsigned long[size];
2235 
2236  unsigned long *nPointTotal_r = new unsigned long[size];
2237  unsigned long *nPointDomainTotal_r = new unsigned long[size];
2238  unsigned long *nPointGhost_r = new unsigned long[size];
2239  unsigned long *nPointPeriodic_r = new unsigned long[size];
2240  unsigned long *nElemTotal_r = new unsigned long[size];
2241  unsigned long *nElemTriangle_r = new unsigned long[size];
2242  unsigned long *nElemQuadrilateral_r = new unsigned long[size];
2243  unsigned long *nElemTetrahedron_r = new unsigned long[size];
2244  unsigned long *nElemHexahedron_r = new unsigned long[size];
2245  unsigned long *nElemPrism_r = new unsigned long[size];
2246  unsigned long *nElemPyramid_r = new unsigned long[size];
2247 
2248  /*--- Counters needed to track numbers of points, elements, etc. ---*/
2249 
2250  unsigned long nPointTotal_r_tot=0;
2251  unsigned long nPointDomainTotal_r_tot=0;
2252  unsigned long nPointGhost_r_tot=0;
2253  unsigned long nPointPeriodic_r_tot=0;
2254  unsigned long nElemTotal_r_tot=0;
2255  unsigned long nElemTriangle_r_tot=0;
2256  unsigned long nElemQuadrilateral_r_tot=0;
2257  unsigned long nElemTetrahedron_r_tot=0;
2258  unsigned long nElemHexahedron_r_tot=0;
2259  unsigned long nElemPrism_r_tot=0;
2260  unsigned long nElemPyramid_r_tot=0;
2261 
2262  unsigned long Buffer_Size_Coord = 0;
2263  unsigned long Buffer_Size_Color = 0;
2264  unsigned long Buffer_Size_GlobalPointIndex = 0;
2265  unsigned long Buffer_Size_Triangle = 0;
2266  unsigned long Buffer_Size_Quadrilateral = 0;
2267  unsigned long Buffer_Size_Tetrahedron = 0;
2268  unsigned long Buffer_Size_Hexahedron = 0;
2269  unsigned long Buffer_Size_Prism = 0;
2270  unsigned long Buffer_Size_Pyramid = 0;
2271  unsigned long Buffer_Size_GlobElem = 0;
2272 
2273  unsigned long ElemTotal_Counter = 0;
2274  unsigned long PointTotal_Counter = 0;
2275  unsigned long PointDomain_Counter = 0;
2276 
2277  /*--- WARNING: check the next two counters ---*/
2278  unsigned long PointPeriodic_Counter = 0;
2279  unsigned long PointGhost_Counter = 0;
2280  unsigned long ElemTriangle_Counter = 0;
2281  unsigned long ElemQuadrilateral_Counter = 0;
2282  unsigned long ElemTetrahedron_Counter = 0;
2283  unsigned long ElemHexahedron_Counter = 0;
2284  unsigned long ElemPrism_Counter = 0;
2285  unsigned long ElemPyramid_Counter = 0;
2286 
2287  unsigned long *Local_to_global_Triangle = NULL;
2288  unsigned long *Local_to_global_Quadrilateral = NULL;
2289  unsigned long *Local_to_global_Tetrahedron = NULL;
2290  unsigned long *Local_to_global_Hexahedron = NULL;
2291  unsigned long *Local_to_global_Prism = NULL;
2292  unsigned long *Local_to_global_Pyramid = NULL;
2293 
2294  map<unsigned long,bool> Triangle_presence;
2295  map<unsigned long,bool> Quadrilateral_presence;
2296  map<unsigned long,bool> Tetrahedron_presence;
2297  map<unsigned long,bool> Hexahedron_presence;
2298  map<unsigned long,bool> Prism_presence;
2299  map<unsigned long,bool> Pyramid_presence;
2300 
2301  su2double *Buffer_Receive_Coord_loc = NULL;
2302 
2303  unsigned long *Buffer_Receive_Color_loc = NULL;
2304  unsigned long *Buffer_Receive_GlobalPointIndex_loc = NULL;
2305  unsigned long *Buffer_Receive_Triangle_loc = NULL;
2306  unsigned long *Buffer_Receive_Quadrilateral_loc = NULL;
2307  unsigned long *Buffer_Receive_Tetrahedron_loc = NULL;
2308  unsigned long *Buffer_Receive_Hexahedron_loc = NULL;
2309  unsigned long *Buffer_Receive_Prism_loc = NULL;
2310  unsigned long *Buffer_Receive_Pyramid_loc = NULL;
2311 
2312  unsigned long *Buffer_Receive_GlobElem_loc = NULL;
2313  unsigned long *Buffer_Receive_Triangle_presence_loc = NULL;
2314  unsigned long *Buffer_Receive_Quadrilateral_presence_loc = NULL;
2315  unsigned long *Buffer_Receive_Tetrahedron_presence_loc = NULL;
2316  unsigned long *Buffer_Receive_Hexahedron_presence_loc = NULL;
2317  unsigned long *Buffer_Receive_Prism_presence_loc = NULL;
2318  unsigned long *Buffer_Receive_Pyramid_presence_loc = NULL;
2319 
2320  /*--- Allocate the memory that we only need if we have MPI support ---*/
2321 
2322 #ifdef HAVE_MPI
2323 
2324  su2double *Buffer_Receive_Coord = NULL;
2325 
2326  unsigned long *Buffer_Receive_Color = NULL;
2327  unsigned long *Buffer_Receive_GlobalPointIndex = NULL;
2328  unsigned long *Buffer_Receive_Triangle = NULL;
2329  unsigned long *Buffer_Receive_Quadrilateral = NULL;
2330  unsigned long *Buffer_Receive_Tetrahedron = NULL;
2331  unsigned long *Buffer_Receive_Hexahedron = NULL;
2332  unsigned long *Buffer_Receive_Prism = NULL;
2333  unsigned long *Buffer_Receive_Pyramid = NULL;
2334  unsigned long *Buffer_Receive_GlobElem = NULL;
2335 
2336  unsigned long **Buffer_Receive_Triangle_presence = new unsigned long*[size];
2337  unsigned long **Buffer_Receive_Quadrilateral_presence = new unsigned long*[size];
2338  unsigned long **Buffer_Receive_Tetrahedron_presence = new unsigned long*[size];
2339  unsigned long **Buffer_Receive_Hexahedron_presence = new unsigned long*[size];
2340  unsigned long **Buffer_Receive_Prism_presence = new unsigned long*[size];
2341  unsigned long **Buffer_Receive_Pyramid_presence = new unsigned long*[size];
2342 
2343 #endif
2344 
2345  /*--- Basic dimensionalization ---*/
2346 
2347  nDomain = size;
2348 
2349  Marker_All_SendRecv = new short[nMarker_Max];
2350  nSendDomain_Periodic = new unsigned long [nDomain];
2351  nReceivedDomain_Periodic = new unsigned long [nDomain];
2352 
2353  /*--- Auxiliar vector based on the original geometry ---*/
2354 
2355  ElemIn = new bool[geometry->GetnElem()];
2356 
2357  /*--- Define some mapping variables ---*/
2358  map<unsigned long,bool> PointIn;
2359  map<unsigned long,unsigned long> Global_to_local_Point_recv;
2360 
2361  Buffer_Send_nDim = geometry->GetnDim();
2362  Buffer_Send_nZone = geometry->GetnZone();
2363 
2364  /*--- Divide the elements in color list to speed up the grid partitioning ---*/
2365 
2366  map<unsigned long,unsigned long> Local_to_global_elem;
2367  for (unsigned long i=0; i<geometry->GetGlobal_nElem(); i++) {
2368  map<unsigned long, unsigned long>::const_iterator MI = geometry->Global_to_Local_Elem.find(i);
2369  if (MI != geometry->Global_to_Local_Elem.end()) {
2370  Local_to_global_elem[geometry->Global_to_Local_Elem[i]] = i;
2371  }
2372  }
2373 
2374  /*--- MEMORY WARNING: Bad usage of memory here for local_colour_values. Not scalable.
2375  In the future, we should avoid sharing a single array of all colors in all nodes. ---*/
2376  unsigned long *local_colour_values = new unsigned long[geometry->GetGlobal_nPoint()];
2377  unsigned long *local_colour_temp = new unsigned long[geometry->ending_node[rank]-geometry->starting_node[rank]];
2378 
2379  for (unsigned long i=0; i<geometry->ending_node[rank]-geometry->starting_node[rank]; i++) {
2380  local_colour_temp[i]=geometry->node[i]->GetColor();
2381  local_colour_values[geometry->starting_node[rank]+i]=local_colour_temp[i];
2382  }
2383 
2384  /*--- Communicate the grid coloring to all partitions. This information
2385  will be repeatedly used throughout the organization of the partitions
2386  and sorting out their ghost points/elements. ---*/
2387 
2388 #ifdef HAVE_MPI
2389 
2390  int comm_counter=0;
2391  for (iDomain=0; iDomain < (unsigned long)size; iDomain++) {
2392  if (iDomain != (unsigned long)rank) {
2393  SU2_MPI::Isend(local_colour_temp, geometry->ending_node[rank]-geometry->starting_node[rank],
2394  MPI_UNSIGNED_LONG, iDomain, iDomain, MPI_COMM_WORLD, &send_req[comm_counter]);
2395  comm_counter++;
2396  }
2397  }
2398 
2399  for (iDomain=0; iDomain < (unsigned long)size-1; iDomain++) {
2401  source = status2.MPI_SOURCE;
2402  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
2403  SU2_MPI::Recv(&local_colour_values[geometry->starting_node[source]], recv_count,
2404  MPI_UNSIGNED_LONG, source, rank, MPI_COMM_WORLD, &status2);
2405  }
2406 
2407  /*--- Wait for the sends to complete (will be true since we're using
2408  blocking recv's above. ---*/
2409 
2410  SU2_MPI::Waitall(size-1, send_req, send_stat);
2411 
2412 #endif
2413 
2414  /*--- Free temporary buffer for communicating colors. ---*/
2415 
2416  delete [] local_colour_temp;
2417 
2418 #ifdef HAVE_MPI
2420 #endif
2421 
2422  /*--- This loop gets the array sizes of points, elements, etc. for each
2423  rank to send to each other rank. ---*/
2424 
2425  for (iDomain = 0; iDomain < nDomain; iDomain++) {
2426 
2427  /*--- Interior dimensionalization. Loop over the original grid to
2428  perform the dimensionalizaton of the domain variables ---*/
2429 
2430  Buffer_Send_nElemTotal = 0;
2431  Buffer_Send_nPointTotal = 0;
2432  Buffer_Send_nPointGhost = 0;
2433  Buffer_Send_nPointDomainTotal = 0;
2434  Buffer_Send_nPointPeriodic = 0;
2435  Buffer_Send_nElemTriangle = 0;
2436  Buffer_Send_nElemQuadrilateral = 0;
2437  Buffer_Send_nElemTetrahedron = 0;
2438  Buffer_Send_nElemHexahedron = 0;
2439  Buffer_Send_nElemPrism = 0;
2440  Buffer_Send_nElemPyramid = 0;
2441 
2442  /*--- Initialize the global to local mapping ---*/
2443 
2444  PointIn.clear();
2445 
2446  /*--- Loop over all of the local elements and count the number of each
2447  type of point and element that needs to be sent. ---*/
2448 
2449  for (iElem = 0; iElem < geometry->GetnElem(); iElem++) {
2450 
2451  /*--- Check if the element belongs to the domain ---*/
2452 
2453  ElemIn[iElem] = false;
2454  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
2455  iPoint = geometry->elem[iElem]->GetNode(iNode);
2456  if (local_colour_values[iPoint] == iDomain) {
2457  ElemIn[iElem] = true; break;
2458  }
2459  }
2460 
2461  /*--- If this element is needed by iDomain, get information
2462  about the number of points and element type. ---*/
2463 
2464  if (ElemIn[iElem]) {
2465 
2466  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
2467  iPoint = geometry->elem[iElem]->GetNode(iNode);
2468 
2469  /*--- If we haven't already found this point... ---*/
2470 
2471  map<unsigned long, bool>::const_iterator MI = PointIn.find(iPoint);
2472  if (MI == PointIn.end()) {
2473 
2474  /*--- Mark point as found and collect information ---*/
2475 
2476  PointIn[iPoint] = true;
2477 
2478  if ((iPoint >= geometry->starting_node[rank]) &&
2479  (iPoint < geometry->ending_node[rank])) {
2480 
2481  Buffer_Send_nPointTotal++;
2482 
2483  /*--- Increment our counters ---*/
2484  if ( local_colour_values[iPoint] == iDomain ) {
2485  if ( iPoint > geometry->GetGlobal_nPointDomain() - 1)
2486  Buffer_Send_nPointPeriodic++;
2487  else
2488  Buffer_Send_nPointDomainTotal++;
2489  }
2490  else Buffer_Send_nPointGhost++;
2491 
2492 
2493  }
2494  }
2495  }
2496 
2497  /*--- Increment the counter for the current type of element ---*/
2498 
2499  switch(geometry->elem[iElem]->GetVTK_Type()) {
2500  case TRIANGLE: Buffer_Send_nElemTriangle++; break;
2501  case QUADRILATERAL: Buffer_Send_nElemQuadrilateral++; break;
2502  case TETRAHEDRON: Buffer_Send_nElemTetrahedron++; break;
2503  case HEXAHEDRON: Buffer_Send_nElemHexahedron++; break;
2504  case PRISM: Buffer_Send_nElemPrism++; break;
2505  case PYRAMID: Buffer_Send_nElemPyramid++; break;
2506  }
2507 
2508  /*--- Increment the total number of elements for iDomain ---*/
2509 
2510  Buffer_Send_nElemTotal++;
2511 
2512  }
2513  }
2514 
2515  /*--- Store the counts on a partition by partition basis. ---*/
2516 
2517  nDim_s[iDomain] = geometry->GetnDim();
2518  nZone_s[iDomain] = Buffer_Send_nZone;
2519  nPointTotal_s[iDomain] = Buffer_Send_nPointTotal;
2520  nPointDomainTotal_s[iDomain] = Buffer_Send_nPointDomainTotal;
2521  nPointGhost_s[iDomain] = Buffer_Send_nPointGhost;
2522  nPointPeriodic_s[iDomain] = Buffer_Send_nPointPeriodic;
2523  nElemTotal_s[iDomain] = Buffer_Send_nElemTotal;
2524  nElemTriangle_s[iDomain] = Buffer_Send_nElemTriangle;
2525  nElemQuadrilateral_s[iDomain] = Buffer_Send_nElemQuadrilateral;
2526  nElemTetrahedron_s[iDomain] = Buffer_Send_nElemTetrahedron;
2527  nElemHexahedron_s[iDomain] = Buffer_Send_nElemHexahedron;
2528  nElemPrism_s[iDomain] = Buffer_Send_nElemPrism;
2529  nElemPyramid_s[iDomain] = Buffer_Send_nElemPyramid;
2530 
2531  /*--- Total counts for allocating send buffers below ---*/
2532 
2533  Buffer_Size_Coord += nPointTotal_s[iDomain]*nDim_s[iDomain];
2534  Buffer_Size_Color += nPointTotal_s[iDomain];
2535  Buffer_Size_GlobalPointIndex += nPointTotal_s[iDomain];
2536  Buffer_Size_Triangle += nElemTriangle_s[iDomain];
2537  Buffer_Size_Quadrilateral += nElemQuadrilateral_s[iDomain];
2538  Buffer_Size_Tetrahedron += nElemTetrahedron_s[iDomain];
2539  Buffer_Size_Hexahedron += nElemHexahedron_s[iDomain];
2540  Buffer_Size_Prism += nElemPrism_s[iDomain];
2541  Buffer_Size_Pyramid += nElemPyramid_s[iDomain];
2542  Buffer_Size_GlobElem += nElemTotal_s[iDomain];
2543 
2544  }
2545 
2546  /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/
2547 
2548  Buffer_Send_Coord = new su2double[Buffer_Size_Coord];
2549 
2550  Buffer_Send_Color = new unsigned long[Buffer_Size_Color];
2551  Buffer_Send_GlobalPointIndex = new unsigned long[Buffer_Size_GlobalPointIndex];
2552  Buffer_Send_Triangle = new unsigned long[Buffer_Size_Triangle*N_POINTS_TRIANGLE];
2553  Buffer_Send_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral*N_POINTS_QUADRILATERAL];
2554  Buffer_Send_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron*N_POINTS_TETRAHEDRON];
2555  Buffer_Send_Hexahedron = new unsigned long[Buffer_Size_Hexahedron*N_POINTS_HEXAHEDRON];
2556  Buffer_Send_Prism = new unsigned long[Buffer_Size_Prism*N_POINTS_PRISM];
2557  Buffer_Send_Pyramid = new unsigned long[Buffer_Size_Pyramid*N_POINTS_PYRAMID];
2558  Buffer_Send_GlobElem = new unsigned long[Buffer_Size_GlobElem];
2559 
2560  Local_to_global_Triangle = new unsigned long[Buffer_Size_Triangle];
2561  Local_to_global_Quadrilateral = new unsigned long[Buffer_Size_Quadrilateral];
2562  Local_to_global_Tetrahedron = new unsigned long[Buffer_Size_Tetrahedron];
2563  Local_to_global_Hexahedron = new unsigned long[Buffer_Size_Hexahedron];
2564  Local_to_global_Prism = new unsigned long[Buffer_Size_Prism];
2565  Local_to_global_Pyramid = new unsigned long[Buffer_Size_Pyramid];
2566 
2567  /*--- Initialize the counters for the larger send buffers (by domain) ---*/
2568 
2569  ElemTotal_Counter = 0;
2570  PointTotal_Counter = 0;
2571  PointDomain_Counter = 0;
2572  /*--- WARNING: check the next two counters ---*/
2573  PointPeriodic_Counter = 0;
2574  PointGhost_Counter = 0;
2575  ElemTriangle_Counter = 0;
2576  ElemQuadrilateral_Counter = 0;
2577  ElemTetrahedron_Counter = 0;
2578  ElemHexahedron_Counter = 0;
2579  ElemPrism_Counter = 0;
2580  ElemPyramid_Counter = 0;
2581 
2582  /*--- Now that we know the sizes of the point, elem, etc. arrays, we can
2583  allocate and send the information in large chunks to all processors. ---*/
2584 
2585  for (iDomain = 0; iDomain < nDomain; iDomain++) {
2586 
2587  /*--- A rank does not communicate with itself through MPI ---*/
2588 
2589  if ((unsigned long)rank != iDomain) {
2590 
2591 #ifdef HAVE_MPI
2592 
2593  /*--- Communicate the counts to iDomain with non-blocking sends ---*/
2594 
2595  SU2_MPI::Isend(&nDim_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain,
2596  iDomain*13+0, MPI_COMM_WORLD, &send_req[0]);
2597 
2598  SU2_MPI::Isend(&nZone_s[iDomain], 1, MPI_UNSIGNED_SHORT, iDomain,
2599  iDomain*13+1, MPI_COMM_WORLD, &send_req[1]);
2600 
2601  SU2_MPI::Isend(&nPointTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2602  iDomain*13+2, MPI_COMM_WORLD, &send_req[2]);
2603 
2604  SU2_MPI::Isend(&nPointDomainTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2605  iDomain*13+3, MPI_COMM_WORLD, &send_req[3]);
2606 
2607  SU2_MPI::Isend(&nPointGhost_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2608  iDomain*13+4, MPI_COMM_WORLD, &send_req[4]);
2609 
2610  SU2_MPI::Isend(&nPointPeriodic_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2611  iDomain*13+5, MPI_COMM_WORLD, &send_req[5]);
2612 
2613  SU2_MPI::Isend(&nElemTotal_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2614  iDomain*13+6, MPI_COMM_WORLD, &send_req[6]);
2615 
2616  SU2_MPI::Isend(&nElemTriangle_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2617  iDomain*13+7, MPI_COMM_WORLD, &send_req[7]);
2618 
2619  SU2_MPI::Isend(&nElemQuadrilateral_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2620  iDomain*13+8, MPI_COMM_WORLD, &send_req[8]);
2621 
2622  SU2_MPI::Isend(&nElemTetrahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2623  iDomain*13+9, MPI_COMM_WORLD, &send_req[9]);
2624 
2625  SU2_MPI::Isend(&nElemHexahedron_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2626  iDomain*13+10, MPI_COMM_WORLD, &send_req[10]);
2627 
2628  SU2_MPI::Isend(&nElemPrism_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2629  iDomain*13+11, MPI_COMM_WORLD, &send_req[11]);
2630 
2631  SU2_MPI::Isend(&nElemPyramid_s[iDomain], 1, MPI_UNSIGNED_LONG, iDomain,
2632  iDomain*13+12, MPI_COMM_WORLD, &send_req[12]);
2633 
2634 #endif
2635 
2636  } else {
2637 
2638  /*--- If iDomain = rank, we simply copy values into place in memory ---*/
2639 
2640  nDim = nDim_s[iDomain];
2641  nZone = nZone_s[iDomain];
2642 
2643  // nPointTotal = nPointTotal_s[iDomain];
2644  // nPointDomainTotal = nPointDomainTotal_s[iDomain];
2645  // nPointGhost = nPointGhost_s[iDomain];
2646  // nPointPeriodic = nPointPeriodic_s[iDomain];
2647  // nElemTotal = nElemTotal_s[iDomain];
2648  // nElemTriangle = nElemTriangle_s[iDomain];
2649  // nElemQuadrilateral = nElemQuadrilateral_s[iDomain];
2650  // nElemTetrahedron = nElemTetrahedron_s[iDomain];
2651  // nElemHexahedron = nElemHexahedron_s[iDomain];
2652  // nElemPrism = nElemPrism_s[iDomain];
2653  // nElemPyramid = nElemPyramid_s[iDomain];
2654 
2655  nDim_r[iDomain] = nDim_s[iDomain];
2656  nZone_r[iDomain] = nZone_s[iDomain];
2657  nPointTotal_r[iDomain] = nPointTotal_s[iDomain];
2658  nPointDomainTotal_r[iDomain] = nPointDomainTotal_s[iDomain];
2659  nPointPeriodic_r[iDomain] = nPointPeriodic_s[iDomain];
2660  nElemTotal_r[iDomain] = nElemTotal_s[iDomain];
2661  nElemTriangle_r[iDomain] = nElemTriangle_s[iDomain];
2662  nElemQuadrilateral_r[iDomain] = nElemQuadrilateral_s[iDomain];
2663  nElemTetrahedron_r[iDomain] = nElemTetrahedron_s[iDomain];
2664  nElemHexahedron_r[iDomain] = nElemHexahedron_s[iDomain];
2665  nElemPrism_r[iDomain] = nElemPrism_s[iDomain];
2666  nElemPyramid_r[iDomain] = nElemPyramid_s[iDomain];
2667 
2668  nPointTotal_r_tot += nPointTotal_r[iDomain];
2669  nPointDomainTotal_r_tot += nPointDomainTotal_r[iDomain];
2670  nPointGhost_r_tot += nPointGhost_r[iDomain];
2671  nPointPeriodic_r_tot += nPointPeriodic_r[iDomain];
2672  nElemTotal_r_tot += nElemTotal_r[iDomain];
2673  nElemTriangle_r_tot += nElemTriangle_r[iDomain];
2674  nElemQuadrilateral_r_tot += nElemQuadrilateral_r[iDomain];
2675  nElemTetrahedron_r_tot += nElemTetrahedron_r[iDomain];
2676  nElemHexahedron_r_tot += nElemHexahedron_r[iDomain];
2677  nElemPrism_r_tot += nElemPrism_r[iDomain];
2678  nElemPyramid_r_tot += nElemPyramid_r[iDomain];
2679 
2680  }
2681 
2682  /*--- Receive the counts. All processors are sending their counters to
2683  iDomain up above, so only iDomain needs to perform the recv here from
2684  all other ranks. ---*/
2685 
2686  if ((unsigned long)rank == iDomain) {
2687 
2688  for (jDomain = 0; jDomain < (unsigned long)size; jDomain++) {
2689 
2690  /*--- A rank does not communicate with itself through MPI ---*/
2691 
2692  if ((unsigned long)rank != jDomain) {
2693 
2694 #ifdef HAVE_MPI
2695 
2696  /*--- Recv the data for the current sender, jDomain. ---*/
2697 
2698  SU2_MPI::Recv(&nDim_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain,
2699  rank*13+0, MPI_COMM_WORLD, &status2);
2700 
2701  SU2_MPI::Recv(&nZone_r[jDomain], 1, MPI_UNSIGNED_SHORT, jDomain,
2702  rank*13+1, MPI_COMM_WORLD, &status2);
2703 
2704  SU2_MPI::Recv(&nPointTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2705  rank*13+2, MPI_COMM_WORLD, &status2);
2706 
2707  SU2_MPI::Recv(&nPointDomainTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2708  rank*13+3, MPI_COMM_WORLD, &status2);
2709 
2710  SU2_MPI::Recv(&nPointGhost_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2711  rank*13+4, MPI_COMM_WORLD, &status2);
2712 
2713  SU2_MPI::Recv(&nPointPeriodic_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2714  rank*13+5, MPI_COMM_WORLD, &status2);
2715 
2716  SU2_MPI::Recv(&nElemTotal_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2717  rank*13+6, MPI_COMM_WORLD, &status2);
2718 
2719  SU2_MPI::Recv(&nElemTriangle_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2720  rank*13+7, MPI_COMM_WORLD, &status2);
2721 
2722  SU2_MPI::Recv(&nElemQuadrilateral_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2723  rank*13+8, MPI_COMM_WORLD, &status2);
2724 
2725  SU2_MPI::Recv(&nElemTetrahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2726  rank*13+9, MPI_COMM_WORLD, &status2);
2727 
2728  SU2_MPI::Recv(&nElemHexahedron_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2729  rank*13+10, MPI_COMM_WORLD, &status2);
2730 
2731  SU2_MPI::Recv(&nElemPrism_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2732  rank*13+11, MPI_COMM_WORLD, &status2);
2733 
2734  SU2_MPI::Recv(&nElemPyramid_r[jDomain], 1, MPI_UNSIGNED_LONG, jDomain,
2735  rank*13+12, MPI_COMM_WORLD, &status2);
2736 
2737 #endif
2738 
2739  /*--- These are the cumulative totals that we will recv below. ----*/
2740 
2741  nPointTotal_r_tot += nPointTotal_r[jDomain];
2742  nPointDomainTotal_r_tot += nPointDomainTotal_r[jDomain];
2743  nPointGhost_r_tot += nPointGhost_r[jDomain];
2744  nPointPeriodic_r_tot += nPointPeriodic_r[jDomain];
2745  nElemTotal_r_tot += nElemTotal_r[jDomain];
2746  nElemTriangle_r_tot += nElemTriangle_r[jDomain];
2747  nElemQuadrilateral_r_tot += nElemQuadrilateral_r[jDomain];
2748  nElemTetrahedron_r_tot += nElemTetrahedron_r[jDomain];
2749  nElemHexahedron_r_tot += nElemHexahedron_r[jDomain];
2750  nElemPrism_r_tot += nElemPrism_r[jDomain];
2751  nElemPyramid_r_tot += nElemPyramid_r[jDomain];
2752 
2753  }
2754  }
2755 
2756  }
2757  }
2758 
2759  for (iDomain = 0; iDomain < nDomain; iDomain++) {
2760 
2761  /*--- Wait for the non-blocking sends to complete. ---*/
2762 
2763 #ifdef HAVE_MPI
2764  if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(13, send_req, send_stat);
2766 #endif
2767 
2768  }
2769 
2770  for (iDomain = 0; iDomain < nDomain; iDomain++) {
2771 
2772  /*--- Above was number of elements to send and receive, and here is where
2773  we send/recv the actual elements. Here you're sending global index values,
2774  which are later changed to local. ---*/
2775 
2776  /*--- Set the value of the interior geometry. Initialize counters. ---*/
2777 
2778  iElemTotal = 0;
2779  iPointTotal = 0;
2780  iPointDomain = 0;
2781  iPointPeriodic = nPointDomainTotal_s[iDomain];
2782  iPointGhost = nPointDomainTotal_s[iDomain] + nPointPeriodic_s[iDomain];
2783  iElemTriangle = 0;
2784  iElemQuadrilateral = 0;
2785  iElemTetrahedron = 0;
2786  iElemHexahedron = 0;
2787  iElemPrism = 0;
2788  iElemPyramid = 0;
2789 
2790  /*--- Initialize the global to local mapping ---*/
2791 
2792  PointIn.clear();
2793 
2794  /*--- Load up the actual elements into the buffers for sending. ---*/
2795 
2796  for (iElem = 0; iElem < geometry->GetnElem(); iElem++) {
2797 
2798  /*--- Check if the element belongs to the domain ---*/
2799 
2800  ElemIn[iElem] = false;
2801  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
2802  iPoint = geometry->elem[iElem]->GetNode(iNode);
2803  if (local_colour_values[iPoint] == iDomain) {
2804  ElemIn[iElem] = true; break;
2805  }
2806  }
2807 
2808  /*--- If this element should be sent ---*/
2809 
2810  if (ElemIn[iElem]) {
2811 
2812  /*--- We need to send this element, so add it to the send buffer. The
2813  local to global mapping has already been done as a class data member. ---*/
2814 
2815  Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal] = Local_to_global_elem[iElem];
2816 
2817  /*--- Loop through the nodes of the current element ---*/
2818 
2819  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
2820 
2821  /*--- Get the global index for this node in the element ---*/
2822  iPoint = geometry->elem[iElem]->GetNode(iNode);
2823 
2824  /*--- Store the connectivity for this element for each node ---*/
2825  vnodes_local[iNode] = iPoint;
2826 
2827  /*--- Check if this point has been found previously ---*/
2828 
2829  map<unsigned long, bool>::const_iterator MI = PointIn.find(iPoint);
2830  if (MI == PointIn.end()) {
2831 
2832  /*--- Check if this node lives on the current rank based on the
2833  initial linear partitioning. We are only ever sending nodes that
2834  we own in the linear partitioning (no duplicate nodes are sent) ---*/
2835 
2836  if ((iPoint >= geometry->starting_node[rank]) &&
2837  (iPoint < geometry->ending_node[rank])) {
2838 
2839  /*--- Decide whether this is an interior, periodic, or ghost node ---*/
2840 
2841  if (local_colour_values[iPoint] == iDomain) {
2842 
2843  /*--- If iDomain owns the point, it must be either an interior
2844  node (iPoint < nPointDomain) or a periodic node. ---*/
2845 
2846  if (iPoint > geometry->GetGlobal_nPointDomain() - 1)
2847  iPointCurrent = iPointPeriodic;
2848  else
2849  iPointCurrent = iPointDomain;
2850 
2851  } else {
2852 
2853  /*--- Otherwise, it must be a ghost point for iDomain ---*/
2854  iPointCurrent = iPointGhost;
2855 
2856  }
2857 
2858  /*--- Setting global to local, the color, and index. ---*/
2859 
2860  PointIn[iPoint] = true;
2861 
2862  Buffer_Send_Color[PointTotal_Counter+iPointCurrent] = local_colour_values[iPoint];
2863  Buffer_Send_GlobalPointIndex[PointTotal_Counter+iPointCurrent] = iPoint;
2864 
2865  /*--- Get the coordinates for this point ---*/
2866 
2867  for (iDim = 0; iDim < nDim_s[iDomain]; iDim++) {
2868 
2869  /*--- iPoint is the global index, but we store everything local
2870  to this rank. So we need to subtract the starting index. All
2871  ranks re-index their points from zero. ---*/
2872  Buffer_Send_Coord[nDim_s[iDomain]*(PointTotal_Counter+iPointCurrent)+iDim] = geometry->node[iPoint-geometry->starting_node[rank]]->GetCoord(iDim);
2873  }
2874 
2875  /*--- Increment our counters ---*/
2876  if ( local_colour_values[iPoint] == iDomain ) {
2877  if ( iPoint > geometry->GetGlobal_nPointDomain() - 1)
2878  iPointPeriodic++;
2879  else
2880  iPointDomain++;
2881  }
2882  else iPointGhost++;
2883 
2884  /*--- Increment the total number of points we're sending ---*/
2885  iPointTotal++;
2886 
2887  }
2888  }
2889  }
2890 
2891  /*--- Load the connectivity for the current element into the send buffer.
2892  Also store the local to global mapping for the elements.
2893  Note that we are using the vnode_local array we filled above to store
2894  the connectivity. Loop through each element type. ---*/
2895 
2896  switch(geometry->elem[iElem]->GetVTK_Type()) {
2897  case TRIANGLE:
2898  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2899  Buffer_Send_Triangle[3*(ElemTriangle_Counter+iElemTriangle)+iNode] = vnodes_local[iNode];
2900  Local_to_global_Triangle[ElemTriangle_Counter+iElemTriangle] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2901  iElemTriangle++; break;
2902  case QUADRILATERAL:
2903  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2904  Buffer_Send_Quadrilateral[4*(ElemQuadrilateral_Counter+iElemQuadrilateral)+iNode] = vnodes_local[iNode];
2905  Local_to_global_Quadrilateral[ElemQuadrilateral_Counter+iElemQuadrilateral] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2906  iElemQuadrilateral++; break;
2907  case TETRAHEDRON:
2908  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2909  Buffer_Send_Tetrahedron[4*(ElemTetrahedron_Counter+iElemTetrahedron)+iNode] = vnodes_local[iNode];
2910  Local_to_global_Tetrahedron[ElemTetrahedron_Counter+iElemTetrahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2911  iElemTetrahedron++; break;
2912  case HEXAHEDRON:
2913  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2914  Buffer_Send_Hexahedron[8*(ElemHexahedron_Counter+iElemHexahedron)+iNode] = vnodes_local[iNode];
2915  Local_to_global_Hexahedron[ElemHexahedron_Counter+iElemHexahedron] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2916  iElemHexahedron++; break;
2917  case PRISM:
2918  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2919  Buffer_Send_Prism[6*(ElemPrism_Counter+iElemPrism)+iNode] = vnodes_local[iNode];
2920  Local_to_global_Prism[ElemPrism_Counter+iElemPrism] =Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2921  iElemPrism++; break;
2922  case PYRAMID:
2923  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++)
2924  Buffer_Send_Pyramid[5*(ElemPyramid_Counter+iElemPyramid)+iNode] = vnodes_local[iNode];
2925  Local_to_global_Pyramid[ElemPyramid_Counter+iElemPyramid] = Buffer_Send_GlobElem[ElemTotal_Counter+iElemTotal];
2926  iElemPyramid++; break;
2927  }
2928 
2929  /*--- Regardless of the type, increment the total count ---*/
2930  iElemTotal++;
2931 
2932  }
2933  }
2934 
2935  /*--- Send the buffers with the geometrical information ---*/
2936 
2937  if (iDomain != (unsigned long)rank) {
2938 
2939 #ifdef HAVE_MPI
2940 
2941  /*--- Communicate the coordinates, global index, colors, and element
2942  date to iDomain with non-blocking sends. ---*/
2943 
2944  SU2_MPI::Isend(&Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]],
2945  nPointTotal_s[iDomain]*nDim_s[iDomain], MPI_DOUBLE, iDomain,
2946  iDomain*16+0, MPI_COMM_WORLD, &send_req[0]);
2947 
2948  SU2_MPI::Isend(&Buffer_Send_GlobalPointIndex[PointTotal_Counter],
2949  nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2950  iDomain*16+1, MPI_COMM_WORLD, &send_req[1]);
2951 
2952  SU2_MPI::Isend(&Buffer_Send_Color[PointTotal_Counter],
2953  nPointTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2954  iDomain*16+2, MPI_COMM_WORLD, &send_req[2]);
2955 
2956  SU2_MPI::Isend(&Buffer_Send_Triangle[ElemTriangle_Counter*3],
2957  nElemTriangle_s[iDomain]*3, MPI_UNSIGNED_LONG, iDomain,
2958  iDomain*16+3, MPI_COMM_WORLD, &send_req[3]);
2959 
2960  SU2_MPI::Isend(&Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*4],
2961  nElemQuadrilateral_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain,
2962  iDomain*16+4, MPI_COMM_WORLD, &send_req[4]);
2963 
2964  SU2_MPI::Isend(&Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*4],
2965  nElemTetrahedron_s[iDomain]*4, MPI_UNSIGNED_LONG, iDomain,
2966  iDomain*16+5, MPI_COMM_WORLD, &send_req[5]);
2967 
2968  SU2_MPI::Isend(&Buffer_Send_Hexahedron[ElemHexahedron_Counter*8],
2969  nElemHexahedron_s[iDomain]*8, MPI_UNSIGNED_LONG, iDomain,
2970  iDomain*16+6, MPI_COMM_WORLD, &send_req[6]);
2971 
2972  SU2_MPI::Isend(&Buffer_Send_Prism[ElemPrism_Counter*6],
2973  nElemPrism_s[iDomain]*6, MPI_UNSIGNED_LONG, iDomain,
2974  iDomain*16+7, MPI_COMM_WORLD, &send_req[7]);
2975 
2976  SU2_MPI::Isend(&Buffer_Send_Pyramid[ElemPyramid_Counter*5],
2977  nElemPyramid_s[iDomain]*5, MPI_UNSIGNED_LONG, iDomain,
2978  iDomain*16+8, MPI_COMM_WORLD, &send_req[8]);
2979 
2980  SU2_MPI::Isend(&Buffer_Send_GlobElem[ElemTotal_Counter],
2981  nElemTotal_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2982  iDomain*16+9, MPI_COMM_WORLD, &send_req[9]);
2983 
2984  SU2_MPI::Isend(&Local_to_global_Triangle[ElemTriangle_Counter],
2985  nElemTriangle_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2986  iDomain*16+10, MPI_COMM_WORLD, &send_req[10]);
2987 
2988  SU2_MPI::Isend(&Local_to_global_Quadrilateral[ElemQuadrilateral_Counter],
2989  nElemQuadrilateral_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2990  iDomain*16+11, MPI_COMM_WORLD, &send_req[11]);
2991 
2992  SU2_MPI::Isend(&Local_to_global_Tetrahedron[ElemTetrahedron_Counter],
2993  nElemTetrahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2994  iDomain*16+12, MPI_COMM_WORLD, &send_req[12]);
2995 
2996  SU2_MPI::Isend(&Local_to_global_Hexahedron[ElemHexahedron_Counter],
2997  nElemHexahedron_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
2998  iDomain*16+13, MPI_COMM_WORLD, &send_req[13]);
2999 
3000  SU2_MPI::Isend(&Local_to_global_Prism[ElemPrism_Counter],
3001  nElemPrism_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
3002  iDomain*16+14, MPI_COMM_WORLD, &send_req[14]);
3003 
3004  SU2_MPI::Isend(&Local_to_global_Pyramid[ElemPyramid_Counter],
3005  nElemPyramid_s[iDomain], MPI_UNSIGNED_LONG, iDomain,
3006  iDomain*16+15, MPI_COMM_WORLD, &send_req[15]);
3007 
3008 #endif
3009 
3010  } else {
3011 
3012  /*--- Allocate local memory for the local recv of the elements ---*/
3013 
3014  Buffer_Receive_Coord_loc = new su2double[nPointTotal_s[iDomain]*nDim_s[iDomain]];
3015 
3016  Buffer_Receive_GlobalPointIndex_loc = new unsigned long[nPointTotal_s[iDomain]];
3017  Buffer_Receive_Color_loc = new unsigned long[nPointTotal_s[iDomain]];
3018  Buffer_Receive_Triangle_loc = new unsigned long[nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE];
3019  Buffer_Receive_Quadrilateral_loc = new unsigned long[nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL];
3020  Buffer_Receive_Tetrahedron_loc = new unsigned long[nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON];
3021  Buffer_Receive_Hexahedron_loc = new unsigned long[nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON];
3022  Buffer_Receive_Prism_loc = new unsigned long[nElemPrism_s[iDomain]*N_POINTS_PRISM];
3023  Buffer_Receive_Pyramid_loc = new unsigned long[nElemPyramid_s[iDomain]*N_POINTS_PYRAMID];
3024  Buffer_Receive_GlobElem_loc = new unsigned long[nElemTotal_s[iDomain]];
3025 
3026  Buffer_Receive_Triangle_presence_loc = new unsigned long[nElemTriangle_s[iDomain]];
3027  Buffer_Receive_Quadrilateral_presence_loc = new unsigned long[nElemQuadrilateral_s[iDomain]];
3028  Buffer_Receive_Tetrahedron_presence_loc = new unsigned long[nElemTetrahedron_s[iDomain]];
3029  Buffer_Receive_Hexahedron_presence_loc = new unsigned long[nElemHexahedron_s[iDomain]];
3030  Buffer_Receive_Prism_presence_loc = new unsigned long[nElemPrism_s[iDomain]];
3031  Buffer_Receive_Pyramid_presence_loc = new unsigned long[nElemPyramid_s[iDomain]];
3032 
3033  for (iter = 0; iter < nPointTotal_s[iDomain]*nDim_s[iDomain]; iter++)
3034  Buffer_Receive_Coord_loc[iter] = Buffer_Send_Coord[PointTotal_Counter*nDim_s[iDomain]+iter];
3035 
3036  for (iter = 0; iter < nPointTotal_s[iDomain]; iter++) {
3037  Buffer_Receive_GlobalPointIndex_loc[iter] = Buffer_Send_GlobalPointIndex[PointTotal_Counter+iter];
3038  Buffer_Receive_Color_loc[iter] = Buffer_Send_Color[PointTotal_Counter+iter];
3039  }
3040 
3041  for (iter = 0; iter < nElemTriangle_s[iDomain]*N_POINTS_TRIANGLE; iter++)
3042  Buffer_Receive_Triangle_loc[iter] = Buffer_Send_Triangle[ElemTriangle_Counter*N_POINTS_TRIANGLE+iter];
3043 
3044  for (iter = 0; iter < nElemQuadrilateral_s[iDomain]*N_POINTS_QUADRILATERAL; iter++)
3045  Buffer_Receive_Quadrilateral_loc[iter] = Buffer_Send_Quadrilateral[ElemQuadrilateral_Counter*N_POINTS_QUADRILATERAL+iter];
3046 
3047  for (iter = 0; iter < nElemTetrahedron_s[iDomain]*N_POINTS_TETRAHEDRON; iter++)
3048  Buffer_Receive_Tetrahedron_loc[iter] = Buffer_Send_Tetrahedron[ElemTetrahedron_Counter*N_POINTS_TETRAHEDRON+iter];
3049 
3050  for (iter = 0; iter < nElemHexahedron_s[iDomain]*N_POINTS_HEXAHEDRON; iter++)
3051  Buffer_Receive_Hexahedron_loc[iter] = Buffer_Send_Hexahedron[ElemHexahedron_Counter*N_POINTS_HEXAHEDRON+iter];
3052 
3053  for (iter = 0; iter < nElemPrism_s[iDomain]*N_POINTS_PRISM; iter++)
3054  Buffer_Receive_Prism_loc[iter] = Buffer_Send_Prism[ElemPrism_Counter*N_POINTS_PRISM+iter];
3055 
3056  for (iter = 0; iter < nElemPyramid_s[iDomain]*N_POINTS_PYRAMID; iter++)
3057  Buffer_Receive_Pyramid_loc[iter] = Buffer_Send_Pyramid[ElemPyramid_Counter*N_POINTS_PYRAMID+iter];
3058 
3059  for (unsigned long i=0; i<nElemTotal_s[iDomain]; i++) {
3060  Buffer_Receive_GlobElem_loc[i]=Buffer_Send_GlobElem[ElemTotal_Counter+i];
3061  }
3062 
3063  for (unsigned long i=0; i<nElemTriangle_s[iDomain]; i++) {
3064  Buffer_Receive_Triangle_presence_loc[i]=Local_to_global_Triangle[ElemTriangle_Counter+i];
3065  }
3066 
3067  for (unsigned long i=0; i<nElemQuadrilateral_s[iDomain]; i++) {
3068  Buffer_Receive_Quadrilateral_presence_loc[i]=Local_to_global_Quadrilateral[ElemQuadrilateral_Counter+i];
3069  }
3070 
3071  for (unsigned long i=0; i<nElemTetrahedron_s[iDomain]; i++) {
3072  Buffer_Receive_Tetrahedron_presence_loc[i]=Local_to_global_Tetrahedron[ElemTetrahedron_Counter+i];
3073  }
3074 
3075  for (unsigned long i=0; i<nElemHexahedron_s[iDomain]; i++) {
3076  Buffer_Receive_Hexahedron_presence_loc[i]=Local_to_global_Hexahedron[ElemHexahedron_Counter+i];
3077  }
3078 
3079  for (unsigned long i=0; i<nElemPrism_s[iDomain]; i++) {
3080  Buffer_Receive_Prism_presence_loc[i]=Local_to_global_Prism[ElemPrism_Counter+i];
3081  }
3082 
3083  for (unsigned long i=0; i<nElemPyramid_s[iDomain]; i++) {
3084  Buffer_Receive_Pyramid_presence_loc[i]=Local_to_global_Pyramid[ElemPyramid_Counter+i];
3085  }
3086  }
3087 
3088  /*--- Increment the counters for the send buffers (iDomain loop) ---*/
3089 
3090  ElemTotal_Counter += iElemTotal;
3091  PointTotal_Counter += iPointTotal;
3092  PointDomain_Counter += iPointDomain;
3093  /*--- WARNING: check the next two counters ---*/
3094  PointPeriodic_Counter += iPointPeriodic;
3095  PointGhost_Counter += iPointGhost;
3096  ElemTriangle_Counter += iElemTriangle;
3097  ElemQuadrilateral_Counter += iElemQuadrilateral;
3098  ElemTetrahedron_Counter += iElemTetrahedron;
3099  ElemHexahedron_Counter += iElemHexahedron;
3100  ElemPrism_Counter += iElemPrism;
3101  ElemPyramid_Counter += iElemPyramid;
3102 
3103  }
3104 
3105 #ifdef HAVE_MPI
3107 #endif
3108 
3109  /*--- The next section begins the recv of all data for the interior
3110  points/elements in the mesh. First, create the domain structures for
3111  the points on this rank ---*/
3112 
3113  nPoint = nPointTotal_r_tot;
3114  nPointDomain = nPointDomainTotal_r_tot;
3115  nPointNode = nPoint;
3116  node = new CPoint*[nPoint];
3117  Local_to_Global_Point = new long[nPoint];
3118 
3119  /*--- Array initialization ---*/
3120 
3121  for (iPoint = 0; iPoint < nPointTotal_r_tot; iPoint++) {
3122  Local_to_Global_Point[iPoint] = -1;
3123  }
3124 
3125  /*--- Initialize some counters ---*/
3126 
3127  unsigned long temp_node_count = 0;
3128  unsigned long temp_node_count_periodic = nPointDomainTotal_r_tot;
3129  unsigned long temp_node_count_ghost = nPointDomainTotal_r_tot+nPointPeriodic_r_tot;
3130 
3131 
3132  /*--- First, we recv all of the point data ---*/
3133 
3134  for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) {
3135 
3136  if ((unsigned long)rank != iDomain) {
3137 
3138 #ifdef HAVE_MPI
3139 
3140  /*--- Allocate the receive buffer vector. Send the colors so that we
3141  know whether what we recv is an owned or halo node. ---*/
3142 
3143  Buffer_Receive_Coord = new su2double [nPointTotal_r[iDomain]*nDim_r[iDomain]];
3144  Buffer_Receive_Color = new unsigned long [nPointTotal_r[iDomain]];
3145  Buffer_Receive_GlobalPointIndex = new unsigned long [nPointTotal_r[iDomain]];
3146 
3147  /*--- Receive the buffers with the coords, global index, and colors ---*/
3148 
3149  SU2_MPI::Probe(iDomain, rank*16+0, MPI_COMM_WORLD, &status2);
3150  source = status2.MPI_SOURCE;
3151  SU2_MPI::Get_count(&status2, MPI_DOUBLE, &recv_count);
3152  SU2_MPI::Recv(Buffer_Receive_Coord, recv_count , MPI_DOUBLE,
3153  source, rank*16+0, MPI_COMM_WORLD, &status2);
3154 
3155  SU2_MPI::Probe(iDomain, rank*16+1, MPI_COMM_WORLD, &status2);
3156  source = status2.MPI_SOURCE;
3157  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3158  SU2_MPI::Recv(Buffer_Receive_GlobalPointIndex, recv_count, MPI_UNSIGNED_LONG,
3159  source, rank*16+1, MPI_COMM_WORLD, &status2);
3160 
3161  SU2_MPI::Probe(iDomain, rank*16+2, MPI_COMM_WORLD, &status2);
3162  source = status2.MPI_SOURCE;
3163  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3164  SU2_MPI::Recv(Buffer_Receive_Color, recv_count, MPI_UNSIGNED_LONG,
3165  source, rank*16+2, MPI_COMM_WORLD, &status2);
3166 
3167  /*--- Loop over all of the points that we have recv'd and store the
3168  coords, global index, and colors ---*/
3169 
3170  unsigned long index=0;
3171  for (iPoint = 0; iPoint < nPointTotal_r[iDomain]; iPoint++) {
3172 
3173  /*--- If this rank owns the current point ---*/
3174 
3175  if (Buffer_Receive_Color[iPoint] == (unsigned long)rank) {
3176 
3177  /*--- If iDomain owns the point, it must be either an interior
3178  node (iPoint < nPointDomain) or a periodic node. ---*/
3179 
3180  if (Buffer_Receive_GlobalPointIndex[iPoint] > geometry->GetGlobal_nPointDomain() - 1) {
3181 
3182  /*--- Set the starting point for the local index of the recv points.
3183  The temp_node_count increments for the interior nodes, between 0 up
3184  to nPointDomain-1. ---*/
3185  index = temp_node_count_periodic;
3186 
3187  /*--- Get the global index ---*/
3188  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint];
3189 
3190  /*--- Allocating the Point object ---*/
3191  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3192  Buffer_Receive_Coord[iPoint*nDim+1],
3193  Local_to_Global_Point[index], config);
3194  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3195  Buffer_Receive_Coord[iPoint*nDim+1],
3196  Buffer_Receive_Coord[iPoint*nDim+2],
3197  Local_to_Global_Point[index], config);
3198 
3199  /*--- Set the color ---*/
3200  node[index]->SetColor(Buffer_Receive_Color[iPoint]);
3201 
3202  /*--- Increment the interior node counter ---*/
3203  temp_node_count_periodic++;
3204 
3205 
3206  }
3207 
3208  else {
3209 
3210 
3211  /*--- Set the starting point for the local index of the recv points.
3212  The temp_node_count increments for the interior nodes, between 0 up
3213  to nPointDomain-1. ---*/
3214  index = temp_node_count;
3215 
3216  /*--- Get the global index ---*/
3217  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint];
3218 
3219  /*--- Allocating the Point object ---*/
3220  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3221  Buffer_Receive_Coord[iPoint*nDim+1],
3222  Local_to_Global_Point[index], config);
3223  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3224  Buffer_Receive_Coord[iPoint*nDim+1],
3225  Buffer_Receive_Coord[iPoint*nDim+2],
3226  Local_to_Global_Point[index], config);
3227 
3228  /*--- Set the color ---*/
3229  node[index]->SetColor(Buffer_Receive_Color[iPoint]);
3230 
3231  /*--- Increment the interior node counter ---*/
3232  temp_node_count++;
3233 
3234 
3235 
3236 
3237  }
3238 
3239 
3240  } else {
3241 
3242  /*--- Set the starting point for the local index of the recv points.
3243  The temp_node_count_domain increments for the ghost nodes, between
3244  nPointDomain up to nPoint. ---*/
3245 
3246  index=temp_node_count_ghost;
3247 
3248  /*--- Get the global index ---*/
3249  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex[iPoint];
3250 
3251  /*--- Allocating the Point object ---*/
3252  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3253  Buffer_Receive_Coord[iPoint*nDim+1],
3254  Local_to_Global_Point[index], config);
3255  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord[iPoint*nDim+0],
3256  Buffer_Receive_Coord[iPoint*nDim+1],
3257  Buffer_Receive_Coord[iPoint*nDim+2],
3258  Local_to_Global_Point[index], config);
3259 
3260  /*--- Set the color ---*/
3261  node[index]->SetColor(Buffer_Receive_Color[iPoint]);
3262 
3263  /*--- Increment the ghost node counter ---*/
3264  temp_node_count_ghost++;
3265 
3266  }
3267  }
3268 
3269  /*--- Delete memory for recv the point stuff ---*/
3270  delete [] Buffer_Receive_Coord;
3271  delete [] Buffer_Receive_Color;
3272  delete [] Buffer_Receive_GlobalPointIndex;
3273 
3274 #endif
3275 
3276  } else {
3277 
3278  /*--- Recv the point data from ourselves (same procedure as above) ---*/
3279 
3280  unsigned long index = 0;
3281  for (iPoint = 0; iPoint < nPointTotal_r[iDomain]; iPoint++) {
3282 
3283  if (Buffer_Receive_Color_loc[iPoint] == (unsigned long)rank) {
3284 
3285  /*--- If iDomain owns the point, it must be either an interior
3286  node (iPoint < nPointDomain) or a periodic node. ---*/
3287 
3288  if (Buffer_Receive_GlobalPointIndex_loc[iPoint] > geometry->GetGlobal_nPointDomain() - 1) {
3289 
3290  index = temp_node_count_periodic;
3291 
3292  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint];
3293  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3294  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3295  Local_to_Global_Point[index], config);
3296  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3297  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3298  Buffer_Receive_Coord_loc[iPoint*nDim+2],
3299  Local_to_Global_Point[index], config);
3300  node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]);
3301  temp_node_count_periodic++;
3302 
3303 
3304 
3305 
3306  }
3307  else {
3308 
3309  index = temp_node_count;
3310  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint];
3311  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3312  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3313  Local_to_Global_Point[index], config);
3314  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3315  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3316  Buffer_Receive_Coord_loc[iPoint*nDim+2],
3317  Local_to_Global_Point[index], config);
3318  node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]);
3319  temp_node_count++;
3320 
3321 
3322 
3323  }
3324 
3325 
3326  } else {
3327 
3328  index=temp_node_count_ghost;
3329  Local_to_Global_Point[index] = Buffer_Receive_GlobalPointIndex_loc[iPoint];
3330  if ( nDim == 2 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3331  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3332  Local_to_Global_Point[index], config);
3333  if ( nDim == 3 ) node[index] = new CPoint(Buffer_Receive_Coord_loc[iPoint*nDim+0],
3334  Buffer_Receive_Coord_loc[iPoint*nDim+1],
3335  Buffer_Receive_Coord_loc[iPoint*nDim+2],
3336  Local_to_Global_Point[index], config);
3337  node[index]->SetColor(Buffer_Receive_Color_loc[iPoint]);
3338  temp_node_count_ghost++;
3339 
3340  }
3341  }
3342 
3343  delete [] Buffer_Receive_Coord_loc;
3344  delete [] Buffer_Receive_Color_loc;
3345  delete [] Buffer_Receive_GlobalPointIndex_loc;
3346 
3347  }
3348  }
3349 
3350  /*--- Get the global to local mapping ---*/
3351 
3352  for (iPoint = 0; iPoint < nPointTotal_r_tot; iPoint++) {
3353  Global_to_local_Point_recv[Local_to_Global_Point[iPoint]] = iPoint;
3354  }
3355 
3356 #ifdef HAVE_MPI
3358 #endif
3359  /*--- Recv all of the element data. First decide which elements we need to own on each proc ---*/
3360 
3361  iElem = 0;
3362  for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) {
3363 
3364  if ((unsigned long)rank != iDomain) {
3365 
3366 #ifdef HAVE_MPI
3367 
3368  /*--- Allocate memory for the element recv ---*/
3369 
3370  Buffer_Receive_Triangle_presence[iDomain] = new unsigned long[nElemTriangle_r[iDomain]];
3371  Buffer_Receive_Quadrilateral_presence[iDomain] = new unsigned long[nElemQuadrilateral_r[iDomain]];
3372  Buffer_Receive_Tetrahedron_presence[iDomain] = new unsigned long[nElemTetrahedron_r[iDomain]];
3373  Buffer_Receive_Hexahedron_presence[iDomain] = new unsigned long[nElemHexahedron_r[iDomain]];
3374  Buffer_Receive_Prism_presence[iDomain] = new unsigned long[nElemPrism_r[iDomain]];
3375  Buffer_Receive_Pyramid_presence[iDomain] = new unsigned long[nElemPyramid_r[iDomain]];
3376 
3377  /*--- Recv the element data ---*/
3378 
3379  SU2_MPI::Probe(iDomain, rank*16+10, MPI_COMM_WORLD, &status2);
3380  source = status2.MPI_SOURCE;
3381  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3382  SU2_MPI::Recv(&Buffer_Receive_Triangle_presence[iDomain][0],
3383  recv_count, MPI_UNSIGNED_LONG, source,
3384  rank*16+10, MPI_COMM_WORLD, &status2);
3385 
3386  SU2_MPI::Probe(iDomain, rank*16+11, MPI_COMM_WORLD, &status2);
3387  source = status2.MPI_SOURCE;
3388  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3389  SU2_MPI::Recv(&Buffer_Receive_Quadrilateral_presence[iDomain][0],
3390  recv_count, MPI_UNSIGNED_LONG, source,
3391  rank*16+11, MPI_COMM_WORLD, &status2);
3392 
3393  SU2_MPI::Probe(iDomain, rank*16+12, MPI_COMM_WORLD, &status2);
3394  source = status2.MPI_SOURCE;
3395  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3396  SU2_MPI::Recv(&Buffer_Receive_Tetrahedron_presence[iDomain][0],
3397  recv_count, MPI_UNSIGNED_LONG, source,
3398  rank*16+12, MPI_COMM_WORLD, &status2);
3399 
3400  SU2_MPI::Probe(iDomain, rank*16+13, MPI_COMM_WORLD, &status2);
3401  source = status2.MPI_SOURCE;
3402  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3403  SU2_MPI::Recv(&Buffer_Receive_Hexahedron_presence[iDomain][0],
3404  recv_count, MPI_UNSIGNED_LONG, source,
3405  rank*16+13, MPI_COMM_WORLD, &status2);
3406 
3407  SU2_MPI::Probe(iDomain, rank*16+14, MPI_COMM_WORLD, &status2);
3408  source = status2.MPI_SOURCE;
3409  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3410  SU2_MPI::Recv(&Buffer_Receive_Prism_presence[iDomain][0],
3411  recv_count, MPI_UNSIGNED_LONG, source,
3412  rank*16+14, MPI_COMM_WORLD, &status2);
3413 
3414  SU2_MPI::Probe(iDomain, rank*16+15, MPI_COMM_WORLD, &status2);
3415  source = status2.MPI_SOURCE;
3416  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3417  SU2_MPI::Recv(&Buffer_Receive_Pyramid_presence[iDomain][0],
3418  recv_count, MPI_UNSIGNED_LONG, source,
3419  rank*16+15, MPI_COMM_WORLD, &status2);
3420 
3421  /*--- Allocating the elements after the recv ---*/
3422 
3423  for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) {
3424  map<unsigned long, bool>::const_iterator MI = Triangle_presence.find(Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]);
3425  if (MI == Triangle_presence.end()) {
3426  Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true;
3427  iElem++;
3428  }
3429  }
3430 
3431  for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) {
3432  map<unsigned long, bool>::const_iterator MI = Quadrilateral_presence.find(Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]);
3433  if (MI == Quadrilateral_presence.end()) {
3434  Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true;
3435  iElem++;
3436  }
3437  }
3438 
3439  for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) {
3440  map<unsigned long, bool>::const_iterator MI = Tetrahedron_presence.find(Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]);
3441  if (MI == Tetrahedron_presence.end()) {
3442  Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true;
3443  iElem++;
3444  }
3445  }
3446 
3447  for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) {
3448  map<unsigned long, bool>::const_iterator MI = Hexahedron_presence.find(Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]);
3449  if (MI == Hexahedron_presence.end()) {
3450  Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true;
3451  iElem++;
3452  }
3453  }
3454 
3455  for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) {
3456  map<unsigned long, bool>::const_iterator MI = Prism_presence.find(Buffer_Receive_Prism_presence[iDomain][iElemPrism]);
3457  if (MI == Prism_presence.end()) {
3458  Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true;
3459  iElem++;
3460  }
3461  }
3462 
3463  for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) {
3464  map<unsigned long, bool>::const_iterator MI = Pyramid_presence.find(Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]);
3465  if (MI == Pyramid_presence.end()) {
3466  Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true;
3467  iElem++;
3468  }
3469  }
3470 
3471 #endif
3472 
3473  } else {
3474 
3475  /*--- Store the element data from our own local rank info ---*/
3476 
3477  for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) {
3478  map<unsigned long, bool>::const_iterator MI = Triangle_presence.find(Buffer_Receive_Triangle_presence_loc[iElemTriangle]);
3479  if (MI == Triangle_presence.end()) {
3480  Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true;
3481  iElem++;
3482  }
3483  }
3484 
3485  for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) {
3486  map<unsigned long, bool>::const_iterator MI = Quadrilateral_presence.find(Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]);
3487  if (MI == Quadrilateral_presence.end()) {
3488  Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true;
3489  iElem++;
3490  }
3491  }
3492 
3493  for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) {
3494  map<unsigned long, bool>::const_iterator MI = Tetrahedron_presence.find(Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]);
3495  if (MI == Tetrahedron_presence.end()) {
3496  Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true;
3497  iElem++;
3498  }
3499  }
3500 
3501  for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) {
3502  map<unsigned long, bool>::const_iterator MI = Hexahedron_presence.find(Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]);
3503  if (MI == Hexahedron_presence.end()) {
3504  Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true;
3505  iElem++;
3506  }
3507  }
3508 
3509  for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) {
3510  map<unsigned long, bool>::const_iterator MI = Prism_presence.find(Buffer_Receive_Prism_presence_loc[iElemPrism]);
3511  if (MI == Prism_presence.end()) {
3512  Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true;
3513  iElem++;
3514  }
3515  }
3516 
3517  for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) {
3518  map<unsigned long, bool>::const_iterator MI = Pyramid_presence.find(Buffer_Receive_Pyramid_presence_loc[iElemPyramid]);
3519  if (MI == Pyramid_presence.end()) {
3520  Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true;
3521  iElem++;
3522  }
3523  }
3524 
3525  }
3526  }
3527 
3528 #ifdef HAVE_MPI
3530 #endif
3531 
3532  /*--- iElem now contains the number of elements that this processor needs in
3533  total. Now we can complete the recv of the element connectivity and only
3534  store the elements that we need on this particular rank. Initialize space
3535  for the elements on this rank. ---*/
3536 
3537  nElem = iElem; iElem = 0;
3538  elem = new CPrimalGrid*[nElem];
3539  unsigned long iElemTria = 0;
3540  unsigned long iElemRect = 0;
3541  unsigned long iElemTetr = 0;
3542  unsigned long iElemHexa = 0;
3543  unsigned long iElemPris = 0;
3544  unsigned long iElemPyra = 0;
3545 
3546  unsigned long iElemRecv = 0;
3547 
3548  /*--- Reset presence before storing elems now that we know nElem ---*/
3549 
3550  Triangle_presence.clear();
3551  Quadrilateral_presence.clear();
3552  Tetrahedron_presence.clear();
3553  Hexahedron_presence.clear();
3554  Prism_presence.clear();
3555  Pyramid_presence.clear();
3556 
3557  /*--- Now recv all of the element connectivity data ---*/
3558 
3559  for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) {
3560 
3561  if ((unsigned long)rank != iDomain) {
3562 
3563 #ifdef HAVE_MPI
3564 
3565  /*--- Allocate memory for the element recv ---*/
3566 
3567  Buffer_Receive_Triangle = new unsigned long[nElemTriangle_r[iDomain]*N_POINTS_TRIANGLE];
3568  Buffer_Receive_Quadrilateral = new unsigned long[nElemQuadrilateral_r[iDomain]*N_POINTS_QUADRILATERAL];
3569  Buffer_Receive_Tetrahedron = new unsigned long[nElemTetrahedron_r[iDomain]*N_POINTS_TETRAHEDRON];
3570  Buffer_Receive_Hexahedron = new unsigned long[nElemHexahedron_r[iDomain]*N_POINTS_HEXAHEDRON];
3571  Buffer_Receive_Prism = new unsigned long[nElemPrism_r[iDomain]*N_POINTS_PRISM];
3572  Buffer_Receive_Pyramid = new unsigned long[nElemPyramid_r[iDomain]*N_POINTS_PYRAMID];
3573  Buffer_Receive_GlobElem = new unsigned long[nElemTotal_r[iDomain]];
3574 
3575  /*--- Recv the element data ---*/
3576 
3577  SU2_MPI::Probe(iDomain, rank*16+3, MPI_COMM_WORLD, &status2);
3578  source = status2.MPI_SOURCE;
3579  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3580  SU2_MPI::Recv(Buffer_Receive_Triangle, recv_count, MPI_UNSIGNED_LONG,
3581  source, rank*16+3, MPI_COMM_WORLD, &status2);
3582 
3583  SU2_MPI::Probe(iDomain, rank*16+4, MPI_COMM_WORLD, &status2);
3584  source = status2.MPI_SOURCE;
3585  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3586  SU2_MPI::Recv(Buffer_Receive_Quadrilateral, recv_count, MPI_UNSIGNED_LONG,
3587  source, rank*16+4, MPI_COMM_WORLD, &status2);
3588 
3589  SU2_MPI::Probe(iDomain, rank*16+5, MPI_COMM_WORLD, &status2);
3590  source = status2.MPI_SOURCE;
3591  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3592  SU2_MPI::Recv(Buffer_Receive_Tetrahedron, recv_count, MPI_UNSIGNED_LONG,
3593  source, rank*16+5, MPI_COMM_WORLD, &status2);
3594 
3595  SU2_MPI::Probe(iDomain, rank*16+6, MPI_COMM_WORLD, &status2);
3596  source = status2.MPI_SOURCE;
3597  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3598  SU2_MPI::Recv(Buffer_Receive_Hexahedron, recv_count, MPI_UNSIGNED_LONG,
3599  source, rank*16+6, MPI_COMM_WORLD, &status2);
3600 
3601  SU2_MPI::Probe(iDomain, rank*16+7, MPI_COMM_WORLD, &status2);
3602  source = status2.MPI_SOURCE;
3603  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3604  SU2_MPI::Recv(Buffer_Receive_Prism, recv_count, MPI_UNSIGNED_LONG,
3605  source, rank*16+7, MPI_COMM_WORLD, &status2);
3606 
3607  SU2_MPI::Probe(iDomain, rank*16+8, MPI_COMM_WORLD, &status2);
3608  source = status2.MPI_SOURCE;
3609  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3610  SU2_MPI::Recv(Buffer_Receive_Pyramid, recv_count, MPI_UNSIGNED_LONG,
3611  source, rank*16+8, MPI_COMM_WORLD, &status2);
3612 
3613  SU2_MPI::Probe(iDomain, rank*16+9, MPI_COMM_WORLD, &status2);
3614  source = status2.MPI_SOURCE;
3615  SU2_MPI::Get_count(&status2, MPI_UNSIGNED_LONG, &recv_count);
3616  SU2_MPI::Recv(Buffer_Receive_GlobElem, recv_count, MPI_UNSIGNED_LONG,
3617  source, rank*16+9, MPI_COMM_WORLD, &status2);
3618 
3619  /*--- Allocating the elements after the recv. Note that here we are
3620  reusing the presence arrays to make sure that we find the exact same
3621  set of elements that were counted above to get nElem. ---*/
3622 
3623  iElemRecv = 0;
3624 
3625  for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) {
3626  map<unsigned long, bool>::const_iterator MI = Triangle_presence.find(Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]);
3627  if (MI == Triangle_presence.end()) {
3628  Triangle_presence[Buffer_Receive_Triangle_presence[iDomain][iElemTriangle]] = true;
3629  elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+0]],
3630  Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+1]],
3631  Global_to_local_Point_recv[Buffer_Receive_Triangle[iElemTriangle*3+2]], 2);
3632  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3633  iElem++; iElemTria++;
3634  }
3635  iElemRecv++;
3636  }
3637 
3638  for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) {
3639  map<unsigned long, bool>::const_iterator MI = Quadrilateral_presence.find(Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]);
3640  if (MI == Quadrilateral_presence.end()) {
3641  Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence[iDomain][iElemQuadrilateral]] = true;
3642  elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+0]],
3643  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+1]],
3644  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+2]],
3645  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral[iElemQuadrilateral*4+3]], 2);
3646  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3647  iElem++; iElemRect++;
3648  }
3649  iElemRecv++;
3650  }
3651 
3652  for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) {
3653  map<unsigned long, bool>::const_iterator MI = Tetrahedron_presence.find(Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]);
3654  if (MI == Tetrahedron_presence.end()) {
3655  Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence[iDomain][iElemTetrahedron]] = true;
3656  elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+0]],
3657  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+1]],
3658  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+2]],
3659  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron[iElemTetrahedron*4+3]]);
3660  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3661  iElem++; iElemTetr++;
3662  }
3663  iElemRecv++;
3664  }
3665 
3666  for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) {
3667  map<unsigned long, bool>::const_iterator MI = Hexahedron_presence.find(Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]);
3668  if (MI == Hexahedron_presence.end()) {
3669  Hexahedron_presence[Buffer_Receive_Hexahedron_presence[iDomain][iElemHexahedron]] = true;
3670  elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+0]],
3671  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+1]],
3672  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+2]],
3673  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+3]],
3674  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+4]],
3675  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+5]],
3676  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+6]],
3677  Global_to_local_Point_recv[Buffer_Receive_Hexahedron[iElemHexahedron*8+7]]);
3678  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3679  iElem++; iElemHexa++;
3680  }
3681  iElemRecv++;
3682  }
3683 
3684  for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) {
3685  map<unsigned long, bool>::const_iterator MI = Prism_presence.find(Buffer_Receive_Prism_presence[iDomain][iElemPrism]);
3686  if (MI == Prism_presence.end()) {
3687  Prism_presence[Buffer_Receive_Prism_presence[iDomain][iElemPrism]] = true;
3688  elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+0]],
3689  Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+1]],
3690  Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+2]],
3691  Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+3]],
3692  Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+4]],
3693  Global_to_local_Point_recv[Buffer_Receive_Prism[iElemPrism*6+5]]);
3694  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3695  iElem++; iElemPris++;
3696  }
3697  iElemRecv++;
3698  }
3699 
3700  for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) {
3701  map<unsigned long, bool>::const_iterator MI = Pyramid_presence.find(Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]);
3702  if (MI == Pyramid_presence.end()) {
3703  Pyramid_presence[Buffer_Receive_Pyramid_presence[iDomain][iElemPyramid]] = true;
3704  elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+0]],
3705  Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+1]],
3706  Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+2]],
3707  Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+3]],
3708  Global_to_local_Point_recv[Buffer_Receive_Pyramid[iElemPyramid*5+4]]);
3709  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem[iElemRecv]);
3710  iElem++; iElemPyra++;
3711  }
3712  iElemRecv++;
3713  }
3714 
3715  /*--- Free memory for the element data --*/
3716 
3717  delete[] Buffer_Receive_Triangle;
3718  delete[] Buffer_Receive_Quadrilateral;
3719  delete[] Buffer_Receive_Tetrahedron;
3720  delete[] Buffer_Receive_Hexahedron;
3721  delete[] Buffer_Receive_Prism;
3722  delete[] Buffer_Receive_Pyramid;
3723  delete[] Buffer_Receive_GlobElem;
3724 
3725  delete[] Buffer_Receive_Triangle_presence[iDomain];
3726  delete[] Buffer_Receive_Quadrilateral_presence[iDomain];
3727  delete[] Buffer_Receive_Tetrahedron_presence[iDomain];
3728  delete[] Buffer_Receive_Hexahedron_presence[iDomain];
3729  delete[] Buffer_Receive_Prism_presence[iDomain];
3730  delete[] Buffer_Receive_Pyramid_presence[iDomain];
3731 
3732 #endif
3733 
3734  } else {
3735 
3736  /*--- Store the element data from our local rank ---*/
3737 
3738  iElemRecv = 0;
3739 
3740  for (iElemTriangle = 0; iElemTriangle < nElemTriangle_r[iDomain]; iElemTriangle++) {
3741  map<unsigned long, bool>::const_iterator MI = Triangle_presence.find(Buffer_Receive_Triangle_presence_loc[iElemTriangle]);
3742  if (MI == Triangle_presence.end()) {
3743  Triangle_presence[Buffer_Receive_Triangle_presence_loc[iElemTriangle]] = true;
3744  elem[iElem] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+0]],
3745  Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+1]],
3746  Global_to_local_Point_recv[Buffer_Receive_Triangle_loc[iElemTriangle*3+2]], 2);
3747  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3748  iElem++; iElemTria++;
3749  }
3750  iElemRecv++;
3751  }
3752 
3753  for (iElemQuadrilateral = 0; iElemQuadrilateral < nElemQuadrilateral_r[iDomain]; iElemQuadrilateral++) {
3754  map<unsigned long, bool>::const_iterator MI = Quadrilateral_presence.find(Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]);
3755  if (MI == Quadrilateral_presence.end()) {
3756  Quadrilateral_presence[Buffer_Receive_Quadrilateral_presence_loc[iElemQuadrilateral]] = true;
3757  elem[iElem] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+0]],
3758  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+1]],
3759  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+2]],
3760  Global_to_local_Point_recv[Buffer_Receive_Quadrilateral_loc[iElemQuadrilateral*4+3]], 2);
3761  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3762  iElem++; iElemRect++;
3763  }
3764  iElemRecv++;
3765  }
3766 
3767  for (iElemTetrahedron = 0; iElemTetrahedron < nElemTetrahedron_r[iDomain]; iElemTetrahedron++) {
3768  map<unsigned long, bool>::const_iterator MI = Tetrahedron_presence.find(Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]);
3769  if (MI == Tetrahedron_presence.end()) {
3770  Tetrahedron_presence[Buffer_Receive_Tetrahedron_presence_loc[iElemTetrahedron]] = true;
3771  elem[iElem] = new CTetrahedron(Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+0]],
3772  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+1]],
3773  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+2]],
3774  Global_to_local_Point_recv[Buffer_Receive_Tetrahedron_loc[iElemTetrahedron*4+3]]);
3775  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3776  iElem++; iElemTetr++;
3777  }
3778  iElemRecv++;
3779  }
3780 
3781  for (iElemHexahedron = 0; iElemHexahedron < nElemHexahedron_r[iDomain]; iElemHexahedron++) {
3782  map<unsigned long, bool>::const_iterator MI = Hexahedron_presence.find(Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]);
3783  if (MI == Hexahedron_presence.end()) {
3784  Hexahedron_presence[Buffer_Receive_Hexahedron_presence_loc[iElemHexahedron]] = true;
3785  elem[iElem] = new CHexahedron(Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+0]],
3786  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+1]],
3787  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+2]],
3788  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+3]],
3789  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+4]],
3790  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+5]],
3791  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+6]],
3792  Global_to_local_Point_recv[Buffer_Receive_Hexahedron_loc[iElemHexahedron*8+7]]);
3793  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3794  iElem++; iElemHexa++;
3795  }
3796  iElemRecv++;
3797  }
3798 
3799  for (iElemPrism = 0; iElemPrism < nElemPrism_r[iDomain]; iElemPrism++) {
3800  map<unsigned long, bool>::const_iterator MI = Prism_presence.find(Buffer_Receive_Prism_presence_loc[iElemPrism]);
3801  if (MI == Prism_presence.end()) {
3802  Prism_presence[Buffer_Receive_Prism_presence_loc[iElemPrism]] = true;
3803  elem[iElem] = new CPrism(Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+0]],
3804  Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+1]],
3805  Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+2]],
3806  Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+3]],
3807  Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+4]],
3808  Global_to_local_Point_recv[Buffer_Receive_Prism_loc[iElemPrism*6+5]]);
3809  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3810  iElem++; iElemPris++;
3811  }
3812  iElemRecv++;
3813  }
3814 
3815  for (iElemPyramid = 0; iElemPyramid < nElemPyramid_r[iDomain]; iElemPyramid++) {
3816  map<unsigned long, bool>::const_iterator MI = Pyramid_presence.find(Buffer_Receive_Pyramid_presence_loc[iElemPyramid]);
3817  if (MI == Pyramid_presence.end()) {
3818  Pyramid_presence[Buffer_Receive_Pyramid_presence_loc[iElemPyramid]] = true;
3819  elem[iElem] = new CPyramid(Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+0]],
3820  Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+1]],
3821  Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+2]],
3822  Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+3]],
3823  Global_to_local_Point_recv[Buffer_Receive_Pyramid_loc[iElemPyramid*5+4]]);
3824  elem[iElem]->SetGlobalIndex(Buffer_Receive_GlobElem_loc[iElemRecv]);
3825  iElem++; iElemPyra++;
3826  }
3827  iElemRecv++;
3828  }
3829 
3830  /*--- Free memory for element data ---*/
3831 
3832  delete[] Buffer_Receive_Triangle_loc;
3833  delete[] Buffer_Receive_Quadrilateral_loc;
3834  delete[] Buffer_Receive_Tetrahedron_loc;
3835  delete[] Buffer_Receive_Hexahedron_loc;
3836  delete[] Buffer_Receive_Prism_loc;
3837  delete[] Buffer_Receive_Pyramid_loc;
3838  delete[] Buffer_Receive_GlobElem_loc;
3839 
3840  delete[] Buffer_Receive_Triangle_presence_loc;
3841  delete[] Buffer_Receive_Quadrilateral_presence_loc;
3842  delete[] Buffer_Receive_Tetrahedron_presence_loc;
3843  delete[] Buffer_Receive_Hexahedron_presence_loc;
3844  delete[] Buffer_Receive_Prism_presence_loc;
3845  delete[] Buffer_Receive_Pyramid_presence_loc;
3846 
3847  }
3848  }
3849 
3850 #ifdef HAVE_MPI
3851  for (iDomain = 0; iDomain < (unsigned long)size; iDomain++) {
3852  if ((unsigned long)rank != iDomain) SU2_MPI::Waitall(16, send_req, send_stat);
3853  }
3855 #endif
3856 
3857  /*--- Free all of the memory used for communicating points and elements ---*/
3858 
3859  delete [] Buffer_Send_Coord;
3860  delete [] Buffer_Send_GlobalPointIndex;
3861  delete [] Buffer_Send_Color;
3862  delete [] Buffer_Send_Triangle;
3863  delete [] Buffer_Send_Quadrilateral;
3864  delete [] Buffer_Send_Tetrahedron;
3865  delete [] Buffer_Send_Hexahedron;
3866  delete [] Buffer_Send_Prism;
3867  delete [] Buffer_Send_Pyramid;
3868  delete [] Buffer_Send_GlobElem;
3869  delete [] Buffer_Send_BoundLine;
3870  delete [] Buffer_Send_BoundTriangle;
3871  delete [] Buffer_Send_BoundQuadrilateral;
3872  delete [] Buffer_Send_Local2Global_Marker;
3873 
3874  delete [] Buffer_Send_SendDomain_Periodic;
3875  delete [] Buffer_Send_SendDomain_PeriodicTrans;
3876  delete [] Buffer_Send_SendDomain_PeriodicReceptor;
3877  delete [] Buffer_Send_ReceivedDomain_Periodic;
3878  delete [] Buffer_Send_ReceivedDomain_PeriodicTrans;
3879  delete [] Buffer_Send_ReceivedDomain_PeriodicDonor;
3880 
3881 #ifdef HAVE_MPI
3882  delete [] Buffer_Receive_Triangle_presence;
3883  delete [] Buffer_Receive_Quadrilateral_presence;
3884  delete [] Buffer_Receive_Tetrahedron_presence;
3885  delete [] Buffer_Receive_Hexahedron_presence;
3886  delete [] Buffer_Receive_Prism_presence;
3887  delete [] Buffer_Receive_Pyramid_presence;
3888 #endif
3889 
3890  delete [] Local_to_global_Triangle;
3891  delete [] Local_to_global_Quadrilateral;
3892  delete [] Local_to_global_Tetrahedron;
3893  delete [] Local_to_global_Hexahedron;
3894  delete [] Local_to_global_Prism;
3895  delete [] Local_to_global_Pyramid;
3896 
3897 
3898  /*--- Communicate the number of each element type to all processors. These
3899  values are important for merging and writing output later. ---*/
3900 
3901 #ifdef HAVE_MPI
3902  unsigned long Local_nElem = nElem;
3903  SU2_MPI::Allreduce(&Local_nElem, &Global_nElem, 1,
3905 #else
3906  Global_nElem = nElem;
3907 #endif
3908 
3909  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
3910  cout << Global_nElem << " interior elements including halo cells. " << endl;
3911 
3912  /*--- Set the value of Global_nElemDomain (stored in the geometry container that is passed in) ---*/
3913 
3915 
3916  /*--- Store total number of each element type after incrementing the
3917  counters in the recv loop above (to make sure there aren't repeats). ---*/
3918 
3919  nelem_triangle = iElemTria;
3920  nelem_quad = iElemRect;
3921  nelem_tetra = iElemTetr;
3922  nelem_hexa = iElemHexa;
3923  nelem_prism = iElemPris;
3924  nelem_pyramid = iElemPyra;
3925 
3926 #ifdef HAVE_MPI
3927  unsigned long Local_nElemTri = nelem_triangle;
3928  unsigned long Local_nElemQuad = nelem_quad;
3929  unsigned long Local_nElemTet = nelem_tetra;
3930  unsigned long Local_nElemHex = nelem_hexa;
3931  unsigned long Local_nElemPrism = nelem_prism;
3932  unsigned long Local_nElemPyramid = nelem_pyramid;
3933  SU2_MPI::Allreduce(&Local_nElemTri, &Global_nelem_triangle, 1,
3935  SU2_MPI::Allreduce(&Local_nElemQuad, &Global_nelem_quad, 1,
3937  SU2_MPI::Allreduce(&Local_nElemTet, &Global_nelem_tetra, 1,
3939  SU2_MPI::Allreduce(&Local_nElemHex, &Global_nelem_hexa, 1,
3941  SU2_MPI::Allreduce(&Local_nElemPrism, &Global_nelem_prism, 1,
3943  SU2_MPI::Allreduce(&Local_nElemPyramid, &Global_nelem_pyramid, 1,
3945 #else
3952 #endif
3953 
3954  /*--- Print information about the elements to the console ---*/
3955 
3956  if (rank == MASTER_NODE) {
3957  if (Global_nelem_triangle > 0) cout << Global_nelem_triangle << " triangles." << endl;
3958  if (Global_nelem_quad > 0) cout << Global_nelem_quad << " quadrilaterals." << endl;
3959  if (Global_nelem_tetra > 0) cout << Global_nelem_tetra << " tetrahedra." << endl;
3960  if (Global_nelem_hexa > 0) cout << Global_nelem_hexa << " hexahedra." << endl;
3961  if (Global_nelem_prism > 0) cout << Global_nelem_prism << " prisms." << endl;
3962  if (Global_nelem_pyramid > 0) cout << Global_nelem_pyramid << " pyramids." << endl;
3963  }
3964 
3965  /*--- Now partition the boundary elements on the markers. Note that, for
3966  now, we are still performing the boundary partitioning using the master
3967  node alone. The boundaries should make up a much smaller portion of the
3968  mesh, so this is ok for now, but we will transition to a parallel version
3969  of this soon that follows the same procedure above for the interior. ---*/
3970 
3971  if (rank == MASTER_NODE) {
3972 
3973  /*--- Create auxiliary vectors based on the original geometry ---*/
3974 
3975  MarkerIn = new bool[geometry->GetnMarker()];
3976  VertexIn = new bool*[geometry->GetnMarker()];
3977 
3978  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++)
3979  VertexIn[iMarker] = new bool[geometry->GetnElem_Bound(iMarker)];
3980 
3981  Buffer_Send_nDim = geometry->GetnDim();
3982  Buffer_Send_nZone = geometry->GetnZone();
3983  Buffer_Send_nPeriodic = config->GetnPeriodicIndex();
3984  Buffer_Send_Center = new su2double[Buffer_Send_nPeriodic*3];
3985  Buffer_Send_Rotation = new su2double[Buffer_Send_nPeriodic*3];
3986  Buffer_Send_Translate = new su2double[Buffer_Send_nPeriodic*3];
3987 
3988  Buffer_Send_nSendDomain_Periodic = new unsigned long[nDomain];
3989  Buffer_Send_nReceivedDomain_Periodic = new unsigned long[nDomain];
3990 
3991  /*--- Create a local copy of config->GetMarker_All_SendRecv and
3992  config->GetMarker_All_TagBound in the master node ---*/
3993 
3994  Marker_All_SendRecv_Copy = new short[geometry->GetnMarker()];
3995  Marker_All_TagBound_Copy = new string[geometry->GetnMarker()];
3996 
3997  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
3998  Marker_All_SendRecv_Copy[iMarker] = config->GetMarker_All_SendRecv(iMarker);
3999  Marker_All_TagBound_Copy[iMarker] = config->GetMarker_All_TagBound(iMarker);
4000  }
4001 
4002  }
4003 
4004  for (iDomain = 0; iDomain < nDomain; iDomain++) {
4005 
4006  if (rank == MASTER_NODE) {
4007 
4008  /*--- Interior dimensionalization. Loop over the original grid
4009  to perform the dimensionalizaton of the domain variables ---*/
4010 
4011  // Buffer_Send_nElemTotal = 0;
4012  // Buffer_Send_nPointTotal = 0;
4013  // Buffer_Send_nPointGhost = 0;
4014  // Buffer_Send_nPointDomainTotal = 0;
4015  // Buffer_Send_nPointPeriodic = 0;
4016  // Buffer_Send_nElemTriangle = 0;
4017  // Buffer_Send_nElemQuadrilateral = 0;
4018  // Buffer_Send_nElemTetrahedron = 0;
4019  // Buffer_Send_nElemHexahedron = 0;
4020  // Buffer_Send_nElemPrism = 0;
4021  // Buffer_Send_nElemPyramid = 0;
4022 
4023  /*--- Boundary dimensionalization. Dimensionalization with physical
4024  boundaries, compute Buffer_Send_nMarkerDomain,
4025  Buffer_Send_nVertexDomain[nMarkerDomain] ---*/
4026 
4027  Buffer_Send_nMarkerDomain = 0;
4028  Buffer_Send_nBoundLineTotal = 0;
4029  Buffer_Send_nBoundTriangleTotal = 0;
4030  Buffer_Send_nBoundQuadrilateralTotal = 0;
4031 
4032  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
4033  Buffer_Send_nVertexDomain[iMarker] = 0;
4034  Buffer_Send_nBoundLine[iMarker] = 0;
4035  Buffer_Send_nBoundTriangle[iMarker] = 0;
4036  Buffer_Send_nBoundQuadrilateral[iMarker] = 0;
4037  Buffer_Send_Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker];
4038  SPRINTF(&Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE], "%s",
4039  Marker_All_TagBound_Copy[iMarker].c_str());
4040  }
4041 
4042  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
4043  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) {
4044 
4045  MarkerIn[iMarker] = false;
4046  Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain] = 0;
4047 
4048  for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) {
4049  VertexIn[iMarker][iVertex] = false;
4050  for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) {
4051  iPoint = geometry->bound[iMarker][iVertex]->GetNode(iNode);
4052  if (local_colour_values[iPoint] == iDomain) VertexIn[iMarker][iVertex] = true;
4053  }
4054 
4055  /*--- If this vertex should be sent, increment the element type ---*/
4056  if (VertexIn[iMarker][iVertex]) {
4057  switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) {
4058  case LINE:
4059  Buffer_Send_nBoundLine[Buffer_Send_nMarkerDomain]++;
4060  Buffer_Send_nBoundLineTotal++;
4061  break;
4062  case TRIANGLE:
4063  Buffer_Send_nBoundTriangle[Buffer_Send_nMarkerDomain]++;
4064  Buffer_Send_nBoundTriangleTotal++;
4065  break;
4066  case QUADRILATERAL:
4067  Buffer_Send_nBoundQuadrilateral[Buffer_Send_nMarkerDomain]++;
4068  Buffer_Send_nBoundQuadrilateralTotal++;
4069  break;
4070  }
4071 
4072  /*--- Increment the total number of vertices to be sent ---*/
4073  Buffer_Send_nVertexDomain[Buffer_Send_nMarkerDomain]++;
4074  MarkerIn[iMarker] = true;
4075 
4076  }
4077  }
4078 
4079  /*--- Increment the number of markers to be sent ---*/
4080  if (MarkerIn[iMarker]) { Buffer_Send_nMarkerDomain++; }
4081 
4082  }
4083  }
4084 
4085  /*--- Copy periodic information from the config file ---*/
4086 
4087  for (iPeriodic = 0; iPeriodic < Buffer_Send_nPeriodic; iPeriodic++) {
4088  for (iDim = 0; iDim < 3; iDim++) {
4089  Buffer_Send_Center[iDim+iPeriodic*3] = config->GetPeriodicCenter(iPeriodic)[iDim];
4090  Buffer_Send_Rotation[iDim+iPeriodic*3] = config->GetPeriodicRotation(iPeriodic)[iDim];
4091  Buffer_Send_Translate[iDim+iPeriodic*3] = config->GetPeriodicTranslate(iPeriodic)[iDim];
4092  }
4093  }
4094 
4095  /*--- Dimensionalization of the periodic auxiliary vectors ---*/
4096 
4097  for (jDomain = 0; jDomain < nDomain; jDomain++) {
4098  Buffer_Send_nSendDomain_Periodic[jDomain] = 0;
4099  Buffer_Send_nReceivedDomain_Periodic[jDomain] = 0;
4100  }
4101  Buffer_Send_nTotalSendDomain_Periodic = 0;
4102  Buffer_Send_nTotalReceivedDomain_Periodic = 0;
4103 
4104  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
4105  if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) {
4106  for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) {
4107  iPoint = geometry->bound[iMarker][iVertex]->GetNode(0);
4108  if (iDomain == local_colour_values[iPoint]) {
4109 
4110  if (config->GetMarker_All_SendRecv(iMarker) > 0) {
4111 
4112  /*--- Identify the color of the receptor ---*/
4113 
4114  for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) {
4115  if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) &&
4116  (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) {
4117  jPoint = geometry->bound[jMarker][iVertex]->GetNode(0);
4118  ReceptorColor = local_colour_values[jPoint];
4119  }
4120  }
4121 
4122  Buffer_Send_nSendDomain_Periodic[ReceptorColor]++;
4123  Buffer_Send_nTotalSendDomain_Periodic++;
4124 
4125  }
4126  if (config->GetMarker_All_SendRecv(iMarker) < 0) {
4127 
4128  /*--- Identify the color of the donor ---*/
4129 
4130  for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) {
4131  if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) &&
4132  (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) {
4133  jPoint = geometry->bound[jMarker][iVertex]->GetNode(0);
4134  DonorColor = local_colour_values[jPoint];
4135  }
4136  }
4137 
4138  Buffer_Send_nReceivedDomain_Periodic[DonorColor]++;
4139  Buffer_Send_nTotalReceivedDomain_Periodic++;
4140 
4141  }
4142  }
4143  }
4144  }
4145  }
4146 
4147  /*--- Allocate the buffer vectors in the appropiate domain (master, iDomain) ---*/
4148 
4149  Buffer_Send_BoundLine = new unsigned long[Buffer_Send_nBoundLineTotal*N_POINTS_LINE];
4150  Buffer_Send_BoundTriangle = new unsigned long[Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE];
4151  Buffer_Send_BoundQuadrilateral = new unsigned long[Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL];
4152  Buffer_Send_Local2Global_Marker = new unsigned long[Buffer_Send_nMarkerDomain];
4153 
4154  Buffer_Send_SendDomain_Periodic = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic];
4155  Buffer_Send_SendDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic];
4156  Buffer_Send_SendDomain_PeriodicReceptor = new unsigned long[Buffer_Send_nTotalSendDomain_Periodic];
4157  Buffer_Send_ReceivedDomain_Periodic = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic];
4158  Buffer_Send_ReceivedDomain_PeriodicTrans = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic];
4159  Buffer_Send_ReceivedDomain_PeriodicDonor = new unsigned long[Buffer_Send_nTotalReceivedDomain_Periodic];
4160 
4161  if (iDomain != (unsigned long)MASTER_NODE) {
4162 
4163 #ifdef HAVE_MPI
4164 
4165  SU2_MPI::Isend(&Buffer_Send_nBoundLineTotal, 1,
4166  MPI_UNSIGNED_LONG, iDomain,
4167  0, MPI_COMM_WORLD, &send_req[0]);
4168 
4169  SU2_MPI::Isend(&Buffer_Send_nBoundTriangleTotal, 1,
4170  MPI_UNSIGNED_LONG, iDomain,
4171  1, MPI_COMM_WORLD, &send_req[1]);
4172 
4173  SU2_MPI::Isend(&Buffer_Send_nBoundQuadrilateralTotal, 1,
4174  MPI_UNSIGNED_LONG, iDomain,
4175  2, MPI_COMM_WORLD, &send_req[2]);
4176 
4177  SU2_MPI::Isend(&Buffer_Send_nMarkerDomain, 1,
4178  MPI_UNSIGNED_SHORT, iDomain,
4179  3, MPI_COMM_WORLD, &send_req[3]);
4180 
4181  SU2_MPI::Isend(Buffer_Send_nVertexDomain,
4182  nMarker_Max, MPI_UNSIGNED_LONG, iDomain,
4183  4, MPI_COMM_WORLD, &send_req[4]);
4184 
4185  SU2_MPI::Isend(Buffer_Send_nBoundLine,
4186  nMarker_Max, MPI_UNSIGNED_LONG, iDomain,
4187  5, MPI_COMM_WORLD, &send_req[5]);
4188 
4189  SU2_MPI::Isend(Buffer_Send_nBoundTriangle,
4190  nMarker_Max, MPI_UNSIGNED_LONG, iDomain,
4191  6, MPI_COMM_WORLD, &send_req[6]);
4192 
4193  SU2_MPI::Isend(Buffer_Send_nBoundQuadrilateral,
4194  nMarker_Max, MPI_UNSIGNED_LONG, iDomain,
4195  7, MPI_COMM_WORLD, &send_req[7]);
4196 
4197  SU2_MPI::Isend(Buffer_Send_Marker_All_SendRecv,
4198  nMarker_Max, MPI_SHORT, iDomain,
4199  8, MPI_COMM_WORLD, &send_req[8]);
4200 
4201  SU2_MPI::Isend(Buffer_Send_Marker_All_TagBound,
4202  nMarker_Max*MAX_STRING_SIZE, MPI_CHAR, iDomain,
4203  9, MPI_COMM_WORLD, &send_req[9]);
4204 
4205  SU2_MPI::Isend(&Buffer_Send_nPeriodic,
4206  1, MPI_UNSIGNED_SHORT, iDomain,
4207  10, MPI_COMM_WORLD, &send_req[10]);
4208 
4209  SU2_MPI::Isend(Buffer_Send_Center,
4210  nPeriodic*3, MPI_DOUBLE, iDomain,
4211  11, MPI_COMM_WORLD, &send_req[11]);
4212 
4213  SU2_MPI::Isend(Buffer_Send_Rotation,
4214  nPeriodic*3, MPI_DOUBLE, iDomain,
4215  12, MPI_COMM_WORLD, &send_req[12]);
4216 
4217  SU2_MPI::Isend(Buffer_Send_Translate,
4218  nPeriodic*3, MPI_DOUBLE, iDomain,
4219  13, MPI_COMM_WORLD, &send_req[13]);
4220 
4221  SU2_MPI::Isend(&Buffer_Send_nTotalSendDomain_Periodic,
4222  1, MPI_UNSIGNED_LONG, iDomain,
4223  14, MPI_COMM_WORLD, &send_req[14]);
4224 
4225  SU2_MPI::Isend(&Buffer_Send_nTotalReceivedDomain_Periodic,
4226  1, MPI_UNSIGNED_LONG, iDomain,
4227  15, MPI_COMM_WORLD, &send_req[15]);
4228 
4229  SU2_MPI::Isend(Buffer_Send_nSendDomain_Periodic,
4230  nDomain, MPI_UNSIGNED_LONG, iDomain,
4231  16, MPI_COMM_WORLD, &send_req[16]);
4232 
4233  SU2_MPI::Isend(Buffer_Send_nReceivedDomain_Periodic,
4234  nDomain, MPI_UNSIGNED_LONG, iDomain,
4235  17, MPI_COMM_WORLD, &send_req[17]);
4236 
4237  /*--- Wait for this set of non-blocking comm. to complete ---*/
4238 
4239  SU2_MPI::Waitall(18, send_req, send_stat);
4240 
4241 #endif
4242 
4243  } else {
4244 
4245  /*--- We are the master node, so simply copy values into place ---*/
4246 
4247  nDim = Buffer_Send_nDim;
4248  nZone = Buffer_Send_nZone;
4249 
4250  nPeriodic = Buffer_Send_nPeriodic;
4251  // nPointGhost = Buffer_Send_nPointGhost;
4252  // nPointPeriodic = Buffer_Send_nPointPeriodic;
4253 
4254  nBoundLineTotal = Buffer_Send_nBoundLineTotal;
4255  nBoundTriangleTotal = Buffer_Send_nBoundTriangleTotal;
4256  nBoundQuadrilateralTotal = Buffer_Send_nBoundQuadrilateralTotal;
4257  nMarkerDomain = Buffer_Send_nMarkerDomain;
4258 
4259  for (iMarker = 0; iMarker < nMarker_Max; iMarker++) {
4260  nVertexDomain[iMarker] = Buffer_Send_nVertexDomain[iMarker];
4261  nBoundLine[iMarker] = Buffer_Send_nBoundLine[iMarker];
4262  nBoundTriangle[iMarker] = Buffer_Send_nBoundTriangle[iMarker];
4263  nBoundQuadrilateral[iMarker] = Buffer_Send_nBoundQuadrilateral[iMarker];
4264  Marker_All_SendRecv[iMarker] = Buffer_Send_Marker_All_SendRecv[iMarker];
4265  for (iter = 0; iter < MAX_STRING_SIZE; iter++)
4266  Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter] = Buffer_Send_Marker_All_TagBound[iMarker*MAX_STRING_SIZE+iter];
4267  }
4268 
4269  Buffer_Receive_Center = new su2double[nPeriodic*3];
4270  Buffer_Receive_Rotation = new su2double[nPeriodic*3];
4271  Buffer_Receive_Translate = new su2double[nPeriodic*3];
4272 
4273  for (iter = 0; iter < nPeriodic*3; iter++) {
4274  Buffer_Receive_Center[iter] = Buffer_Send_Center[iter];
4275  Buffer_Receive_Rotation[iter] = Buffer_Send_Rotation[iter];
4276  Buffer_Receive_Translate[iter] = Buffer_Send_Translate[iter];
4277  }
4278 
4279  nTotalSendDomain_Periodic = Buffer_Send_nTotalSendDomain_Periodic;
4280  nTotalReceivedDomain_Periodic = Buffer_Send_nTotalReceivedDomain_Periodic;
4281 
4282  for (iter = 0; iter < nDomain; iter++) {
4283  nSendDomain_Periodic[iter] = Buffer_Send_nSendDomain_Periodic[iter];
4284  nReceivedDomain_Periodic[iter] = Buffer_Send_nReceivedDomain_Periodic[iter];
4285  }
4286 
4287  }
4288  }
4289 
4290  /*--- Each rank now begins to receive information from the master ---*/
4291 
4292  if ((unsigned long)rank == iDomain) {
4293 
4294  /*--- First, receive the size of buffers before receiving the data ---*/
4295 
4296  if (rank != MASTER_NODE) {
4297 
4298 #ifdef HAVE_MPI
4299 
4301  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4302  SU2_MPI::Recv(&nBoundLineTotal, recv_count, MPI_UNSIGNED_LONG,
4303  MASTER_NODE, 0, MPI_COMM_WORLD, &status);
4304 
4306  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4307  SU2_MPI::Recv(&nBoundTriangleTotal, recv_count, MPI_UNSIGNED_LONG,
4308  MASTER_NODE, 1, MPI_COMM_WORLD, &status);
4309 
4311  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4312  SU2_MPI::Recv(&nBoundQuadrilateralTotal, recv_count, MPI_UNSIGNED_LONG,
4313  MASTER_NODE, 2, MPI_COMM_WORLD, &status);
4314 
4316  SU2_MPI::Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count);
4317  SU2_MPI::Recv(&nMarkerDomain, recv_count, MPI_UNSIGNED_LONG,
4318  MASTER_NODE, 3, MPI_COMM_WORLD, &status);
4319 
4321  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4322  SU2_MPI::Recv(nVertexDomain, recv_count, MPI_UNSIGNED_LONG,
4323  MASTER_NODE, 4, MPI_COMM_WORLD, &status);
4324 
4326  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4327  SU2_MPI::Recv(nBoundLine, recv_count, MPI_UNSIGNED_LONG,
4328  MASTER_NODE, 5, MPI_COMM_WORLD, &status);
4329 
4331  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4332  SU2_MPI::Recv(nBoundTriangle, recv_count, MPI_UNSIGNED_LONG,
4333  MASTER_NODE, 6, MPI_COMM_WORLD, &status);
4334 
4336  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4337  SU2_MPI::Recv(nBoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG,
4338  MASTER_NODE, 7, MPI_COMM_WORLD, &status);
4339 
4341  SU2_MPI::Get_count(&status, MPI_SHORT, &recv_count);
4343  MASTER_NODE, 8, MPI_COMM_WORLD, &status);
4344 
4346  SU2_MPI::Get_count(&status, MPI_CHAR, &recv_count);
4347  SU2_MPI::Recv(Marker_All_TagBound, recv_count, MPI_CHAR,
4348  MASTER_NODE, 9, MPI_COMM_WORLD, &status);
4349 
4350  SU2_MPI::Probe(MASTER_NODE, 10, MPI_COMM_WORLD, &status);
4351  SU2_MPI::Get_count(&status, MPI_UNSIGNED_SHORT, &recv_count);
4352  SU2_MPI::Recv(&nPeriodic, recv_count, MPI_UNSIGNED_SHORT,
4353  MASTER_NODE, 10, MPI_COMM_WORLD, &status);
4354 
4355 #endif
4356 
4357  /*--- Marker_All_TagBound and Marker_All_SendRecv, set the same
4358  values in the config files of all the files ---*/
4359 
4360  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
4361  config->SetMarker_All_SendRecv(iMarker,
4362  Marker_All_SendRecv[iMarker]);
4363  config->SetMarker_All_TagBound(iMarker,
4364  string(&Marker_All_TagBound[iMarker*MAX_STRING_SIZE]));
4365  }
4366 
4367 
4368  /*--- Periodic boundary conditions ---*/
4369 
4370  Buffer_Receive_Center = new su2double[nPeriodic*3];
4371  Buffer_Receive_Rotation = new su2double[nPeriodic*3];
4372  Buffer_Receive_Translate = new su2double[nPeriodic*3];
4373 
4374 #ifdef HAVE_MPI
4375 
4376  SU2_MPI::Probe(MASTER_NODE, 11, MPI_COMM_WORLD, &status);
4377  SU2_MPI::Get_count(&status, MPI_DOUBLE, &recv_count);
4378  SU2_MPI::Recv(Buffer_Receive_Center, recv_count, MPI_DOUBLE,
4379  MASTER_NODE, 11, MPI_COMM_WORLD, &status);
4380 
4381  SU2_MPI::Probe(MASTER_NODE, 12, MPI_COMM_WORLD, &status);
4382  SU2_MPI::Get_count(&status, MPI_DOUBLE, &recv_count);
4383  SU2_MPI::Recv(Buffer_Receive_Rotation, recv_count, MPI_DOUBLE,
4384  MASTER_NODE, 12, MPI_COMM_WORLD, &status);
4385 
4386  SU2_MPI::Probe(MASTER_NODE, 13, MPI_COMM_WORLD, &status);
4387  SU2_MPI::Get_count(&status, MPI_DOUBLE, &recv_count);
4388  SU2_MPI::Recv(Buffer_Receive_Translate, recv_count, MPI_DOUBLE,
4389  MASTER_NODE, 13, MPI_COMM_WORLD, &status);
4390 
4391  SU2_MPI::Probe(MASTER_NODE, 14, MPI_COMM_WORLD, &status);
4392  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4393  SU2_MPI::Recv(&nTotalSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4394  MASTER_NODE, 14, MPI_COMM_WORLD, &status);
4395 
4396  SU2_MPI::Probe(MASTER_NODE, 15, MPI_COMM_WORLD, &status);
4397  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4398  SU2_MPI::Recv(&nTotalReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4399  MASTER_NODE, 15, MPI_COMM_WORLD, &status);
4400 
4401  SU2_MPI::Probe(MASTER_NODE, 16, MPI_COMM_WORLD, &status);
4402  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4403  SU2_MPI::Recv(nSendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4404  MASTER_NODE, 16, MPI_COMM_WORLD, &status);
4405 
4406  SU2_MPI::Probe(MASTER_NODE, 17, MPI_COMM_WORLD, &status);
4407  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4408  SU2_MPI::Recv(nReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4409  MASTER_NODE, 17, MPI_COMM_WORLD, &status);
4410 
4411 #endif
4412 
4413  config->SetnPeriodicIndex(nPeriodic);
4414 
4415  for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) {
4416 
4417  su2double* center = new su2double[3];
4418  su2double* rotation = new su2double[3];
4419  su2double* translate = new su2double[3];
4420 
4421  for (iDim = 0; iDim < 3; iDim++) {
4422  center[iDim] = Buffer_Receive_Center[iDim+iPeriodic*3];
4423  rotation[iDim] = Buffer_Receive_Rotation[iDim+iPeriodic*3];
4424  translate[iDim] = Buffer_Receive_Translate[iDim+iPeriodic*3];
4425  }
4426  config->SetPeriodicCenter(iPeriodic, center);
4427  config->SetPeriodicRotation(iPeriodic, rotation);
4428  config->SetPeriodicTranslate(iPeriodic, translate);
4429 
4430  delete [] center; delete [] rotation; delete [] translate;
4431 
4432  }
4433 
4434  }
4435 
4436  delete [] Buffer_Receive_Center;
4437  delete [] Buffer_Receive_Rotation;
4438  delete [] Buffer_Receive_Translate;
4439 
4440  /*--- Allocate the receive buffer vector ---*/
4441 
4442  Buffer_Receive_BoundLine = new unsigned long[nBoundLineTotal*2];
4443  Buffer_Receive_BoundTriangle = new unsigned long[nBoundTriangleTotal*3];
4444  Buffer_Receive_BoundQuadrilateral = new unsigned long[nBoundQuadrilateralTotal*4];
4445  Buffer_Receive_Local2Global_Marker = new unsigned long[nMarkerDomain];
4446 
4447  Buffer_Receive_SendDomain_Periodic = new unsigned long[nTotalSendDomain_Periodic];
4448  Buffer_Receive_SendDomain_PeriodicTrans = new unsigned long[nTotalSendDomain_Periodic];
4449  Buffer_Receive_SendDomain_PeriodicReceptor = new unsigned long[nTotalSendDomain_Periodic];
4450  Buffer_Receive_ReceivedDomain_Periodic = new unsigned long[nTotalReceivedDomain_Periodic];
4451  Buffer_Receive_ReceivedDomain_PeriodicTrans = new unsigned long[nTotalReceivedDomain_Periodic];
4452  Buffer_Receive_ReceivedDomain_PeriodicDonor = new unsigned long[nTotalReceivedDomain_Periodic];
4453 
4454  }
4455 
4456  /*--- Set the value of the Send buffers ---*/
4457 
4458  if (rank == MASTER_NODE) {
4459 
4460  /*--- Set the value of the boundary geometry ---*/
4461 
4462  iMarkerDomain = 0;
4463  iBoundLineTotal = 0; iBoundTriangleTotal = 0; iBoundQuadrilateralTotal = 0;
4464 
4465  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
4466  if ((config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && (MarkerIn[iMarker])) {
4467  for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) {
4468 
4469  if (VertexIn[iMarker][iVertex]) {
4470 
4471  /*--- Send global index here and then convert to local on the recv ---*/
4472 
4473  for (iNode = 0; iNode < geometry->bound[iMarker][iVertex]->GetnNodes(); iNode++) {
4474  vnodes_local[iNode] = geometry->bound[iMarker][iVertex]->GetNode(iNode);
4475  }
4476 
4477  switch(geometry->bound[iMarker][iVertex]->GetVTK_Type()) {
4478  case LINE:
4479  Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+0] = vnodes_local[0];
4480  Buffer_Send_BoundLine[N_POINTS_LINE*iBoundLineTotal+1] = vnodes_local[1];
4481  iBoundLineTotal++;
4482  break;
4483  case TRIANGLE:
4484  Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+0] = vnodes_local[0];
4485  Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+1] = vnodes_local[1];
4486  Buffer_Send_BoundTriangle[N_POINTS_TRIANGLE*iBoundTriangleTotal+2] = vnodes_local[2];
4487  iBoundTriangleTotal++;
4488  break;
4489  case QUADRILATERAL:
4490  Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+0] = vnodes_local[0];
4491  Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+1] = vnodes_local[1];
4492  Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+2] = vnodes_local[2];
4493  Buffer_Send_BoundQuadrilateral[N_POINTS_QUADRILATERAL*iBoundQuadrilateralTotal+3] = vnodes_local[3];
4494  iBoundQuadrilateralTotal++;
4495  break;
4496  }
4497  }
4498  }
4499 
4500  Buffer_Send_Local2Global_Marker[iMarkerDomain] = iMarker;
4501  iMarkerDomain++;
4502 
4503  }
4504  }
4505 
4506  /*--- Evaluate the number of already existing periodic boundary conditions ---*/
4507 
4508  iTotalSendDomain_Periodic = 0;
4509  iTotalReceivedDomain_Periodic = 0;
4510 
4511  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
4512 
4513  if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) {
4514 
4515  for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) {
4516 
4517  iPoint = geometry->bound[iMarker][iVertex]->GetNode(0);
4518  Transformation = geometry->bound[iMarker][iVertex]->GetRotation_Type();
4519 
4520  if (iDomain == local_colour_values[iPoint]) {
4521 
4522  /*--- If the information is going to be sended, find the
4523  domain of the receptor ---*/
4524 
4525  if (config->GetMarker_All_SendRecv(iMarker) > 0) {
4526 
4527  /*--- Identify the color of the receptor ---*/
4528 
4529  for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) {
4530  if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) &&
4531  (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker))) {
4532  jPoint = geometry->bound[jMarker][iVertex]->GetNode(0);
4533  ReceptorColor = local_colour_values[jPoint];
4534  }
4535  }
4536 
4537  /*--- For each color of the receptor we will han an extra marker (+) ---*/
4538 
4539  Buffer_Send_SendDomain_Periodic[iTotalSendDomain_Periodic] = iPoint;
4540  Buffer_Send_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic] = Transformation;
4541  Buffer_Send_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] = ReceptorColor;
4542 
4543  iTotalSendDomain_Periodic++;
4544 
4545  }
4546 
4547  /*--- If the information is goint to be received, find the domain if the donor ---*/
4548 
4549  if (config->GetMarker_All_SendRecv(iMarker) < 0) {
4550 
4551  /*--- Identify the color of the donor ---*/
4552 
4553  for (jMarker = 0; jMarker < geometry->GetnMarker(); jMarker++) {
4554  if ((config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) &&
4555  (config->GetMarker_All_SendRecv(jMarker) == -config->GetMarker_All_SendRecv(iMarker) )) {
4556  jPoint = geometry->bound[jMarker][iVertex]->GetNode(0);
4557  DonorColor = local_colour_values[jPoint];
4558  }
4559  }
4560 
4561  /*--- For each color of the donor we will han an extra marker (-) ---*/
4562 
4563  Buffer_Send_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic] = iPoint;
4564  Buffer_Send_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic] = Transformation;
4565  Buffer_Send_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] = DonorColor;
4566 
4567  iTotalReceivedDomain_Periodic++;
4568 
4569  }
4570  }
4571  }
4572  }
4573  }
4574 
4575  /*--- Send the buffers with the geometrical information ---*/
4576 
4577  if (iDomain != (unsigned long)MASTER_NODE) {
4578 
4579 #ifdef HAVE_MPI
4580 
4581  SU2_MPI::Isend(Buffer_Send_BoundLine,
4582  Buffer_Send_nBoundLineTotal*N_POINTS_LINE, MPI_UNSIGNED_LONG, iDomain,
4583  0, MPI_COMM_WORLD, &send_req[0]);
4584 
4585  SU2_MPI::Isend(Buffer_Send_BoundTriangle,
4586  Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE, MPI_UNSIGNED_LONG, iDomain,
4587  1, MPI_COMM_WORLD, &send_req[1]);
4588 
4589  SU2_MPI::Isend(Buffer_Send_BoundQuadrilateral,
4590  Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL, MPI_UNSIGNED_LONG, iDomain,
4591  2, MPI_COMM_WORLD, &send_req[2]);
4592 
4593  SU2_MPI::Isend(Buffer_Send_Local2Global_Marker,
4594  Buffer_Send_nMarkerDomain, MPI_UNSIGNED_LONG, iDomain,
4595  3, MPI_COMM_WORLD, &send_req[3]);
4596 
4597  SU2_MPI::Isend(Buffer_Send_SendDomain_Periodic,
4598  Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4599  4, MPI_COMM_WORLD, &send_req[4]);
4600 
4601  SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicTrans,
4602  Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4603  5, MPI_COMM_WORLD, &send_req[5]);
4604 
4605  SU2_MPI::Isend(Buffer_Send_SendDomain_PeriodicReceptor,
4606  Buffer_Send_nTotalSendDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4607  6, MPI_COMM_WORLD, &send_req[6]);
4608 
4609  SU2_MPI::Isend(Buffer_Send_ReceivedDomain_Periodic,
4610  Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4611  7, MPI_COMM_WORLD, &send_req[7]);
4612 
4613  SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicTrans,
4614  Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4615  8, MPI_COMM_WORLD, &send_req[8]);
4616 
4617  SU2_MPI::Isend(Buffer_Send_ReceivedDomain_PeriodicDonor,
4618  Buffer_Send_nTotalReceivedDomain_Periodic, MPI_UNSIGNED_LONG, iDomain,
4619  9, MPI_COMM_WORLD, &send_req[9]);
4620 
4621  /*--- Wait for this set of non-blocking comm. to complete ---*/
4622 
4623  SU2_MPI::Waitall(10, send_req, send_stat);
4624 
4625 #endif
4626 
4627  } else {
4628 
4629  /*--- Copy the data directly from our own rank ---*/
4630 
4631  for (iter = 0; iter < Buffer_Send_nBoundLineTotal*N_POINTS_LINE; iter++)
4632  Buffer_Receive_BoundLine[iter] = Buffer_Send_BoundLine[iter];
4633 
4634  for (iter = 0; iter < Buffer_Send_nBoundTriangleTotal*N_POINTS_TRIANGLE; iter++)
4635  Buffer_Receive_BoundTriangle[iter] = Buffer_Send_BoundTriangle[iter];
4636 
4637  for (iter = 0; iter < Buffer_Send_nBoundQuadrilateralTotal*N_POINTS_QUADRILATERAL; iter++)
4638  Buffer_Receive_BoundQuadrilateral[iter] = Buffer_Send_BoundQuadrilateral[iter];
4639 
4640  for (iter = 0; iter < Buffer_Send_nMarkerDomain; iter++)
4641  Buffer_Receive_Local2Global_Marker[iter] = Buffer_Send_Local2Global_Marker[iter];
4642 
4643  for (iter = 0; iter < Buffer_Send_nTotalSendDomain_Periodic; iter++) {
4644  Buffer_Receive_SendDomain_Periodic[iter] = Buffer_Send_SendDomain_Periodic[iter];
4645  Buffer_Receive_SendDomain_PeriodicTrans[iter] = Buffer_Send_SendDomain_PeriodicTrans[iter];
4646  Buffer_Receive_SendDomain_PeriodicReceptor[iter] = Buffer_Send_SendDomain_PeriodicReceptor[iter];
4647  }
4648 
4649  for (iter = 0; iter < Buffer_Send_nTotalReceivedDomain_Periodic; iter++) {
4650  Buffer_Receive_ReceivedDomain_Periodic[iter] = Buffer_Send_ReceivedDomain_Periodic[iter];
4651  Buffer_Receive_ReceivedDomain_PeriodicTrans[iter] = Buffer_Send_ReceivedDomain_PeriodicTrans[iter];
4652  Buffer_Receive_ReceivedDomain_PeriodicDonor[iter] = Buffer_Send_ReceivedDomain_PeriodicDonor[iter];
4653  }
4654 
4655  }
4656 
4657  delete[] Buffer_Send_BoundLine;
4658  delete[] Buffer_Send_BoundTriangle;
4659  delete[] Buffer_Send_BoundQuadrilateral;
4660  delete[] Buffer_Send_Local2Global_Marker;
4661 
4662  delete[] Buffer_Send_SendDomain_Periodic;
4663  delete[] Buffer_Send_SendDomain_PeriodicTrans;
4664  delete[] Buffer_Send_SendDomain_PeriodicReceptor;
4665  delete[] Buffer_Send_ReceivedDomain_Periodic;
4666  delete[] Buffer_Send_ReceivedDomain_PeriodicTrans;
4667  delete[] Buffer_Send_ReceivedDomain_PeriodicDonor;
4668 
4669  }
4670 
4671  if ((unsigned long)rank == iDomain) {
4672 
4673  if (rank != MASTER_NODE) {
4674 
4675  /*--- Receive the buffers with the geometrical information ---*/
4676 
4677 #ifdef HAVE_MPI
4678 
4680  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4681  SU2_MPI::Recv(Buffer_Receive_BoundLine, recv_count, MPI_UNSIGNED_LONG,
4682  MASTER_NODE, 0, MPI_COMM_WORLD, &status);
4683 
4685  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4686  SU2_MPI::Recv(Buffer_Receive_BoundTriangle, recv_count, MPI_UNSIGNED_LONG,
4687  MASTER_NODE, 1, MPI_COMM_WORLD, &status);
4688 
4690  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4691  SU2_MPI::Recv(Buffer_Receive_BoundQuadrilateral, recv_count, MPI_UNSIGNED_LONG,
4692  MASTER_NODE, 2, MPI_COMM_WORLD, &status);
4693 
4695  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4696  SU2_MPI::Recv(Buffer_Receive_Local2Global_Marker, recv_count, MPI_UNSIGNED_LONG,
4697  MASTER_NODE, 3, MPI_COMM_WORLD, &status);
4698 
4700  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4701  SU2_MPI::Recv(Buffer_Receive_SendDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4702  MASTER_NODE, 4, MPI_COMM_WORLD, &status);
4703 
4705  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4706  SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG,
4707  MASTER_NODE, 5, MPI_COMM_WORLD, &status);
4708 
4710  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4711  SU2_MPI::Recv(Buffer_Receive_SendDomain_PeriodicReceptor, recv_count, MPI_UNSIGNED_LONG,
4712  MASTER_NODE, 6, MPI_COMM_WORLD, &status);
4713 
4715  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4716  SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_Periodic, recv_count, MPI_UNSIGNED_LONG,
4717  MASTER_NODE, 7, MPI_COMM_WORLD, &status);
4718 
4720  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4721  SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicTrans, recv_count, MPI_UNSIGNED_LONG,
4722  MASTER_NODE, 8, MPI_COMM_WORLD, &status);
4723 
4725  SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &recv_count);
4726  SU2_MPI::Recv(Buffer_Receive_ReceivedDomain_PeriodicDonor, recv_count, MPI_UNSIGNED_LONG,
4727  MASTER_NODE, 9, MPI_COMM_WORLD, &status);
4728 
4729 #endif
4730 
4731  }
4732 
4733  /*--- Create the domain structures for the boundaries ---*/
4734 
4735  nMarker = nMarkerDomain;
4736  nElem_Bound = new unsigned long[nMarker_Max];
4737  Local_to_Global_Marker = new unsigned short[nMarker_Max];
4738  Tag_to_Marker = new string[nMarker_Max];
4739  string *TagBound_Copy = new string[nMarker_Max];
4740  short *SendRecv_Copy = new short[nMarker_Max];
4741 
4742  for (iMarker = 0; iMarker < nMarker; iMarker++)
4743  nElem_Bound[iMarker] = nVertexDomain[iMarker];
4744 
4745  bound = new CPrimalGrid**[nMarker+(OVERHEAD*size)];
4746  for (iMarker = 0; iMarker < nMarker+(OVERHEAD*size); iMarker++)
4747  bound[iMarker] = NULL;
4748 
4749  for (iMarker = 0; iMarker < nMarker; iMarker++)
4750  bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]];
4751 
4752  /*--- Initialize boundary element counters ---*/
4753  iBoundLineTotal = 0;
4754  iBoundTriangleTotal = 0;
4755  iBoundQuadrilateralTotal = 0;
4756 
4757  /*--- Store the boundary element connectivity. Note here that we have
4758  communicated the global index values for the elements, so we need to
4759  convert this to the local index when instantiating the element. ---*/
4760 
4761  for (iMarker = 0; iMarker < nMarker; iMarker++) {
4762 
4763  iVertexDomain = 0;
4764 
4765  for (iBoundLine = 0; iBoundLine < nBoundLine[iMarker]; iBoundLine++) {
4766  bound[iMarker][iVertexDomain] = new CLine(Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+0]],
4767  Global_to_local_Point_recv[Buffer_Receive_BoundLine[iBoundLineTotal*2+1]], 2);
4768  iVertexDomain++; iBoundLineTotal++;
4769  }
4770  for (iBoundTriangle = 0; iBoundTriangle < nBoundTriangle[iMarker]; iBoundTriangle++) {
4771  bound[iMarker][iVertexDomain] = new CTriangle(Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+0]],
4772  Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+1]],
4773  Global_to_local_Point_recv[Buffer_Receive_BoundTriangle[iBoundTriangleTotal*3+2]], 3);
4774  iVertexDomain++; iBoundTriangleTotal++;
4775  }
4776  for (iBoundQuadrilateral = 0; iBoundQuadrilateral < nBoundQuadrilateral[iMarker]; iBoundQuadrilateral++) {
4777  bound[iMarker][iVertexDomain] = new CQuadrilateral(Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+0]],
4778  Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+1]],
4779  Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+2]],
4780  Global_to_local_Point_recv[Buffer_Receive_BoundQuadrilateral[iBoundQuadrilateralTotal*4+3]], 3);
4781  iVertexDomain++; iBoundQuadrilateralTotal++;
4782  }
4783 
4784  Local_to_Global_Marker[iMarker] = Buffer_Receive_Local2Global_Marker[iMarker];
4785 
4786  /*--- Now each domain has the right information ---*/
4787 
4788  string Grid_Marker = config->GetMarker_All_TagBound(Local_to_Global_Marker[iMarker]);
4789  short SendRecv = config->GetMarker_All_SendRecv(Local_to_Global_Marker[iMarker]);
4790  TagBound_Copy[iMarker] = Grid_Marker;
4791  SendRecv_Copy[iMarker] = SendRecv;
4792 
4793  }
4794 
4795  /*--- Store total number of each boundary element type ---*/
4796 
4797  nelem_edge_bound = iBoundLineTotal;
4798  nelem_triangle_bound = iBoundTriangleTotal;
4799  nelem_quad_bound = iBoundQuadrilateralTotal;
4800 
4801  for (iMarker = 0; iMarker < nMarker; iMarker++) {
4802  config->SetMarker_All_TagBound(iMarker, TagBound_Copy[iMarker]);
4803  config->SetMarker_All_SendRecv(iMarker, SendRecv_Copy[iMarker]);
4804  }
4805 
4806  /*--- Add the new periodic markers to the domain ---*/
4807 
4808  // iTotalSendDomain_Periodic = 0;
4809  // iTotalReceivedDomain_Periodic = 0;
4810 
4811  for (jDomain = 0; jDomain < nDomain; jDomain++) {
4812 
4813  if (nSendDomain_Periodic[jDomain] != 0) {
4814  nVertexDomain[nMarker] = 0;
4815  bound[nMarker] = new CPrimalGrid* [nSendDomain_Periodic[jDomain]];
4816 
4817  iVertex = 0;
4818  for (iTotalSendDomain_Periodic = 0; iTotalSendDomain_Periodic < nTotalSendDomain_Periodic; iTotalSendDomain_Periodic++) {
4819  if (Buffer_Receive_SendDomain_PeriodicReceptor[iTotalSendDomain_Periodic] == jDomain) {
4820  bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_SendDomain_Periodic[iTotalSendDomain_Periodic]], nDim);
4821  bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_SendDomain_PeriodicTrans[iTotalSendDomain_Periodic]);
4822  nVertexDomain[nMarker]++; iVertex++;
4823  }
4824  }
4825 
4826  Marker_All_SendRecv[nMarker] = jDomain+1;
4827  nElem_Bound[nMarker] = nVertexDomain[nMarker];
4828  nMarker++;
4829  }
4830 
4831  if (nReceivedDomain_Periodic[jDomain] != 0) {
4832  nVertexDomain[nMarker] = 0;
4833  bound[nMarker] = new CPrimalGrid* [nReceivedDomain_Periodic[jDomain]];
4834 
4835  iVertex = 0;
4836  for (iTotalReceivedDomain_Periodic = 0; iTotalReceivedDomain_Periodic < nTotalReceivedDomain_Periodic; iTotalReceivedDomain_Periodic++) {
4837  if (Buffer_Receive_ReceivedDomain_PeriodicDonor[iTotalReceivedDomain_Periodic] == jDomain) {
4838  bound[nMarker][iVertex] = new CVertexMPI(Global_to_local_Point_recv[Buffer_Receive_ReceivedDomain_Periodic[iTotalReceivedDomain_Periodic]], nDim);
4839  bound[nMarker][iVertex]->SetRotation_Type(Buffer_Receive_ReceivedDomain_PeriodicTrans[iTotalReceivedDomain_Periodic]);
4840  nVertexDomain[nMarker]++; iVertex++;
4841  }
4842  }
4843 
4844  Marker_All_SendRecv[nMarker] = -(jDomain+1);
4845  nElem_Bound[nMarker] = nVertexDomain[nMarker];
4846  nMarker++;
4847  }
4848 
4849  }
4850 
4851  delete[] TagBound_Copy;
4852  delete[] SendRecv_Copy;
4853 
4854  delete[] Buffer_Receive_BoundLine;
4855  delete[] Buffer_Receive_BoundTriangle;
4856  delete[] Buffer_Receive_BoundQuadrilateral;
4857  delete[] Buffer_Receive_Local2Global_Marker;
4858 
4859  delete[] Buffer_Receive_SendDomain_Periodic;
4860  delete[] Buffer_Receive_SendDomain_PeriodicTrans;
4861  delete[] Buffer_Receive_SendDomain_PeriodicReceptor;
4862  delete[] Buffer_Receive_ReceivedDomain_Periodic;
4863  delete[] Buffer_Receive_ReceivedDomain_PeriodicTrans;
4864  delete[] Buffer_Receive_ReceivedDomain_PeriodicDonor;
4865 
4866  }
4867 
4868  }
4869 
4870  /*--- The MASTER should wait for the sends above to complete ---*/
4871 
4872 #ifdef HAVE_MPI
4874 #endif
4875 
4876  /*--- Set the value of Marker_All_SendRecv and Marker_All_TagBound in the config structure ---*/
4877 
4878  for (iMarker = 0; iMarker < nMarker; iMarker++) {
4879  config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]);
4880  }
4881 
4882  /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/
4883 
4884  unsigned long Local_nPoint = nPoint;
4885  unsigned long Local_nPointDomain = nPointDomain;
4886 
4887 #ifdef HAVE_MPI
4888  SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1,
4890  SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1,
4892 #else
4893  Global_nPoint = Local_nPoint;
4894  Global_nPointDomain = Local_nPointDomain;
4895 #endif
4896 
4897  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
4898  cout << Global_nPoint << " vertices including ghost points. " << endl;
4899 
4900 
4901  for (iMarker = 0; iMarker < nMarker; iMarker++) {
4902  config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]);
4903  }
4904 
4905  /*--- initialize pointers for turbomachinery computations ---*/
4906  nSpanWiseSections = new unsigned short[2];
4907  nSpanSectionsByMarker = new unsigned short[nMarker];
4908  SpanWiseValue = new su2double*[2];
4909  for (iMarker = 0; iMarker < 2; iMarker++){
4910  nSpanWiseSections[iMarker] = 0;
4911  SpanWiseValue[iMarker] = NULL;
4912  }
4913 
4914  nVertexSpan = new long* [nMarker];
4915  nTotVertexSpan = new unsigned long* [nMarker];
4916  turbovertex = new CTurboVertex***[nMarker];
4918  AverageNormal = new su2double**[nMarker];
4919  AverageGridVel = new su2double**[nMarker];
4921  SpanArea = new su2double*[nMarker];
4922  TurboRadius = new su2double*[nMarker];
4926 
4927  for (iMarker = 0; iMarker < nMarker; iMarker++){
4928  nSpanSectionsByMarker[iMarker] = 0;
4929  nVertexSpan[iMarker] = NULL;
4930  nTotVertexSpan[iMarker] = NULL;
4931  turbovertex[iMarker] = NULL;
4932  AverageTurboNormal[iMarker] = NULL;
4933  AverageNormal[iMarker] = NULL;
4934  AverageGridVel[iMarker] = NULL;
4935  AverageTangGridVel[iMarker] = NULL;
4936  SpanArea[iMarker] = NULL;
4937  TurboRadius[iMarker] = NULL;
4938  MaxAngularCoord[iMarker] = NULL;
4939  MinAngularCoord[iMarker] = NULL;
4940  MinRelAngularCoord[iMarker] = NULL;
4941  }
4942 
4943  /*--- initialize pointers for turbomachinery performance computation ---*/
4951 
4952  for (iMarker = 0; iMarker < config->GetnMarker_TurboPerformance(); iMarker++){
4953  TangGridVelIn[iMarker] = NULL;
4954  SpanAreaIn[iMarker] = NULL;
4955  TurboRadiusIn[iMarker] = NULL;
4956  TangGridVelOut[iMarker] = NULL;
4957  SpanAreaOut[iMarker] = NULL;
4958  TurboRadiusOut[iMarker] = NULL;
4959  }
4960 
4961  /*--- Release all of the temporary memory ---*/
4962 
4963  delete [] nDim_s;
4964  delete [] nDim_r;
4965 
4966  delete [] nPointTotal_s;
4967  delete [] nPointDomainTotal_s;
4968  delete [] nPointGhost_s;
4969  delete [] nPointPeriodic_s;
4970  delete [] nElemTotal_s;
4971  delete [] nElemTriangle_s;
4972  delete [] nElemQuadrilateral_s;
4973  delete [] nElemTetrahedron_s;
4974  delete [] nElemHexahedron_s;
4975  delete [] nElemPrism_s;
4976  delete [] nElemPyramid_s;
4977  delete [] nZone_s;
4978 
4979  delete [] nPointTotal_r;
4980  delete [] nPointDomainTotal_r;
4981  delete [] nPointGhost_r;
4982  delete [] nPointPeriodic_r;
4983  delete [] nElemTotal_r;
4984  delete [] nElemTriangle_r;
4985  delete [] nElemQuadrilateral_r;
4986  delete [] nElemTetrahedron_r;
4987  delete [] nElemHexahedron_r;
4988  delete [] nElemPrism_r;
4989  delete [] nElemPyramid_r;
4990  delete [] nZone_r;
4991 
4992  if (rank == MASTER_NODE) {
4993  delete [] MarkerIn;
4994  delete [] Buffer_Send_Center;
4995  delete [] Buffer_Send_Rotation;
4996  delete [] Buffer_Send_Translate;
4997  delete [] Buffer_Send_nSendDomain_Periodic;
4998  delete [] Buffer_Send_nReceivedDomain_Periodic;
4999  delete [] Marker_All_SendRecv_Copy;
5000  delete [] Marker_All_TagBound_Copy;
5001  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++)
5002  delete [] VertexIn[iMarker];
5003  delete[] VertexIn;
5004  }
5005 
5006  delete [] Marker_All_TagBound;
5007  delete [] Buffer_Send_Marker_All_TagBound;
5008 
5009  delete [] nSendDomain_Periodic;
5010  delete [] nReceivedDomain_Periodic;
5011  delete [] nVertexDomain;
5012  delete [] nBoundLine;
5013  delete [] nBoundTriangle;
5014  delete [] nBoundQuadrilateral;
5015  delete [] Buffer_Send_nVertexDomain;
5016  delete [] Buffer_Send_nBoundLine;
5017  delete [] Buffer_Send_nBoundTriangle;
5018  delete [] Buffer_Send_nBoundQuadrilateral;
5019  delete [] Buffer_Send_Marker_All_SendRecv;
5020 
5021 #ifdef HAVE_MPI
5022  delete [] send_stat;
5023  delete [] recv_stat;
5024  delete [] send_req;
5025  delete [] recv_req;
5026 #endif
5027 
5028  delete [] local_colour_values;
5029  delete [] ElemIn;
5030 
5031 }
5032 
5034  CConfig *config,
5035  bool val_flag) {
5036 
5037  /*--- Get rank and size. ---*/
5038 
5039  size = SU2_MPI::GetSize();
5040  rank = SU2_MPI::GetRank();
5041 
5042  /*--- Initialize several class data members for later. ---*/
5043 
5044  Local_to_Global_Point = NULL;
5045  Local_to_Global_Marker = NULL;
5046  Global_to_Local_Marker = NULL;
5047 
5048  /*--- Arrays for defining the linear partitioning. ---*/
5049 
5050  starting_node = NULL;
5051  ending_node = NULL;
5052  npoint_procs = NULL;
5053  nPoint_Linear = NULL;
5054 
5055  /*--- Arrays for defining the turbomachinery structure ---*/
5056 
5057  nSpanWiseSections = NULL;
5058  nSpanSectionsByMarker = NULL;
5059  SpanWiseValue = NULL;
5060  nVertexSpan = NULL;
5061  nTotVertexSpan = NULL;
5062  turbovertex = NULL;
5063  AverageTurboNormal = NULL;
5064  AverageNormal = NULL;
5065  AverageGridVel = NULL;
5066  AverageTangGridVel = NULL;
5067  SpanArea = NULL;
5068  TurboRadius = NULL;
5069  MaxAngularCoord = NULL;
5070  MinAngularCoord = NULL;
5071  MinRelAngularCoord = NULL;
5072 
5073  TangGridVelIn = NULL;
5074  SpanAreaIn = NULL;
5075  TurboRadiusIn = NULL;
5076  TangGridVelOut = NULL;
5077  SpanAreaOut = NULL;
5078  TurboRadiusOut = NULL;
5079 
5080  /*--- Initialize counters for the points/elements local to a rank. ---*/
5081 
5082  nLocal_Point = 0;
5083  nLocal_PointDomain = 0;
5084  nLocal_PointGhost = 0;
5085  nLocal_PointPeriodic = 0;
5086  nLocal_Line = 0;
5087  nLocal_BoundTria = 0;
5088  nLocal_BoundQuad = 0;
5089  nLocal_Tria = 0;
5090  nLocal_Quad = 0;
5091  nLocal_Tetr = 0;
5092  nLocal_Hexa = 0;
5093  nLocal_Pris = 0;
5094  nLocal_Pyra = 0;
5095 
5096  Local_Coords = NULL;
5097  Local_Points = NULL;
5098  Local_Colors = NULL;
5099 
5100  /*--- Arrays for holding the element connectivity. ---*/
5101 
5102  Conn_Line = NULL;
5103  Conn_BoundTria = NULL;
5104  Conn_BoundQuad = NULL;
5105 
5106  Conn_Line_Linear = NULL;
5107  Conn_BoundTria_Linear = NULL;
5108  Conn_BoundQuad_Linear = NULL;
5109 
5110  Conn_Tria = NULL;
5111  Conn_Quad = NULL;
5112  Conn_Tetr = NULL;
5113  Conn_Hexa = NULL;
5114  Conn_Pris = NULL;
5115  Conn_Pyra = NULL;
5116 
5117  /*--- Arrays for holding the element IDs. ---*/
5118 
5119  ID_Line = NULL;
5120  ID_BoundTria = NULL;
5121  ID_BoundQuad = NULL;
5122  ID_Line_Linear = NULL;
5123  ID_BoundTria_Linear = NULL;
5124  ID_BoundQuad_Linear = NULL;
5125 
5126  ID_Tria = NULL;
5127  ID_Quad = NULL;
5128  ID_Tetr = NULL;
5129  ID_Hexa = NULL;
5130  ID_Pris = NULL;
5131  ID_Pyra = NULL;
5132 
5133  Elem_ID_Line = NULL;
5134  Elem_ID_BoundTria = NULL;
5135  Elem_ID_BoundQuad = NULL;
5136  Elem_ID_Line_Linear = NULL;
5137  Elem_ID_BoundTria_Linear = NULL;
5138  Elem_ID_BoundQuad_Linear = NULL;
5139 
5140  /*--- The new geometry class has the same problem dimension/zone. ---*/
5141 
5142  nDim = geometry->GetnDim();
5143  nZone = geometry->GetnZone();
5144 
5145  /*--- Communicate the coloring data so that each rank has a complete set
5146  of colors for all points that reside on it, including repeats. ---*/
5147 
5148  if ((rank == MASTER_NODE) && (size != SINGLE_NODE))
5149  cout <<"Distributing ParMETIS coloring." << endl;
5150 
5151  DistributeColoring(config, geometry);
5152 
5153  /*--- Redistribute the points to all ranks based on the coloring. ---*/
5154 
5155  if ((rank == MASTER_NODE) && (size != SINGLE_NODE))
5156  cout <<"Rebalancing vertices." << endl;
5157 
5158  DistributePoints(config, geometry);
5159 
5160  /*--- Distribute the element information to all ranks based on coloring. ---*/
5161 
5162  if ((rank == MASTER_NODE) && (size != SINGLE_NODE))
5163  cout <<"Rebalancing volume element connectivity." << endl;
5164 
5165  DistributeVolumeConnectivity(config, geometry, TRIANGLE );
5166  DistributeVolumeConnectivity(config, geometry, QUADRILATERAL);
5167  DistributeVolumeConnectivity(config, geometry, TETRAHEDRON );
5168  DistributeVolumeConnectivity(config, geometry, HEXAHEDRON );
5169  DistributeVolumeConnectivity(config, geometry, PRISM );
5170  DistributeVolumeConnectivity(config, geometry, PYRAMID );
5171 
5172  /*--- Distribute the marker information to all ranks based on coloring. ---*/
5173 
5174  if ((rank == MASTER_NODE) && (size != SINGLE_NODE))
5175  cout <<"Rebalancing markers and surface elements." << endl;
5176 
5177  /*--- First, perform a linear partitioning of the marker information, as
5178  the grid readers currently store all boundary information on the master
5179  rank. In the future, this process can be moved directly into the grid
5180  reader to avoid reading the markers to the master rank alone at first. ---*/
5181 
5182  DistributeMarkerTags(config, geometry);
5183  PartitionSurfaceConnectivity(config, geometry, LINE );
5184  PartitionSurfaceConnectivity(config, geometry, TRIANGLE );
5185  PartitionSurfaceConnectivity(config, geometry, QUADRILATERAL);
5186 
5187  /*--- Once the markers are distributed according to the linear partitioning
5188  of the grid points, we can use similar techniques as above for distributing
5189  the surface element connectivity. ---*/
5190 
5191  DistributeSurfaceConnectivity(config, geometry, LINE );
5192  DistributeSurfaceConnectivity(config, geometry, TRIANGLE );
5193  DistributeSurfaceConnectivity(config, geometry, QUADRILATERAL);
5194 
5195  /*--- Reduce the total number of elements that we have on each rank. ---*/
5196 
5197  nLocal_Elem = (nLocal_Tria +
5198  nLocal_Quad +
5199  nLocal_Tetr +
5200  nLocal_Hexa +
5201  nLocal_Pris +
5202  nLocal_Pyra);
5203  nLocal_Bound_Elem = nLocal_Line + nLocal_BoundTria + nLocal_BoundQuad;
5204 #ifndef HAVE_MPI
5205  nGlobal_Elem = nLocal_Elem;
5206  nGlobal_Bound_Elem = nLocal_Bound_Elem;
5207 #else
5208  SU2_MPI::Allreduce(&nLocal_Elem, &nGlobal_Elem, 1,
5210  SU2_MPI::Allreduce(&nLocal_Bound_Elem, &nGlobal_Bound_Elem, 1,
5212 #endif
5213 
5214  /*--- With the distribution of all points, elements, and markers based
5215  on the ParMETIS coloring complete, as a final step, load this data into
5216  our geometry class data structures. ---*/
5217 
5218  LoadPoints(config, geometry);
5219  LoadVolumeElements(config, geometry);
5220  LoadSurfaceElements(config, geometry);
5221 
5222  /*--- Free memory associated with the partitioning of points and elems. ---*/
5223 
5224  Neighbors.clear();
5225  Color_List.clear();
5226 
5227  if (Local_Points != NULL) delete [] Local_Points;
5228  if (Local_Colors != NULL) delete [] Local_Colors;
5229  if (Local_Coords != NULL) delete [] Local_Coords;
5230 
5231  if (nLinear_Line > 0 && Conn_Line_Linear != NULL)
5232  delete [] Conn_Line_Linear;
5233  if (nLinear_BoundTria > 0 && Conn_BoundTria_Linear != NULL)
5234  delete [] Conn_BoundTria_Linear;
5235  if (nLinear_BoundQuad > 0 && Conn_BoundQuad_Linear != NULL)
5236  delete [] Conn_BoundQuad_Linear;
5237 
5238  if (nLocal_Line > 0 && Conn_Line != NULL) delete [] Conn_Line;
5239  if (nLocal_BoundTria > 0 && Conn_BoundTria != NULL) delete [] Conn_BoundTria;
5240  if (nLocal_BoundQuad > 0 && Conn_BoundQuad != NULL) delete [] Conn_BoundQuad;
5241  if (nLocal_Tria > 0 && Conn_Tria != NULL) delete [] Conn_Tria;
5242  if (nLocal_Quad > 0 && Conn_Quad != NULL) delete [] Conn_Quad;
5243  if (nLocal_Tetr > 0 && Conn_Tetr != NULL) delete [] Conn_Tetr;
5244  if (nLocal_Hexa > 0 && Conn_Hexa != NULL) delete [] Conn_Hexa;
5245  if (nLocal_Pris > 0 && Conn_Pris != NULL) delete [] Conn_Pris;
5246  if (nLocal_Pyra > 0 && Conn_Pyra != NULL) delete [] Conn_Pyra;
5247 
5248  if (ID_Line != NULL) delete [] ID_Line;
5249  if (ID_BoundTria != NULL) delete [] ID_BoundTria;
5250  if (ID_BoundQuad != NULL) delete [] ID_BoundQuad;
5251  if (ID_Line_Linear != NULL) delete [] ID_Line_Linear;
5252  if (ID_BoundTria_Linear != NULL) delete [] ID_BoundTria_Linear;
5253  if (ID_BoundQuad_Linear != NULL) delete [] ID_BoundQuad_Linear;
5254 
5255  if (ID_Tria != NULL) delete [] ID_Tria;
5256  if (ID_Quad != NULL) delete [] ID_Quad;
5257  if (ID_Tetr != NULL) delete [] ID_Tetr;
5258  if (ID_Hexa != NULL) delete [] ID_Hexa;
5259  if (ID_Pris != NULL) delete [] ID_Pris;
5260  if (ID_Pyra != NULL) delete [] ID_Pyra;
5261 
5262  if (Elem_ID_Line != NULL) delete [] Elem_ID_Line;
5263  if (Elem_ID_BoundTria != NULL) delete [] Elem_ID_BoundTria;
5264  if (Elem_ID_BoundQuad != NULL) delete [] Elem_ID_BoundQuad;
5265  if (Elem_ID_Line_Linear != NULL) delete [] Elem_ID_Line_Linear;
5266  if (Elem_ID_BoundTria_Linear != NULL) delete [] Elem_ID_BoundTria_Linear;
5267  if (Elem_ID_BoundQuad_Linear != NULL) delete [] Elem_ID_BoundQuad_Linear;
5268 
5269 }
5270 
5272 
5273  if (Local_to_Global_Point != NULL) delete [] Local_to_Global_Point;
5274  if (Global_to_Local_Marker != NULL) delete [] Global_to_Local_Marker;
5275  if (Local_to_Global_Marker != NULL) delete [] Local_to_Global_Marker;
5276 
5277  /*--- Free up memory from turbomachinery performance computation ---*/
5278 
5279  unsigned short iMarker;
5280  if (TangGridVelIn != NULL) {
5281  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5282  if (TangGridVelIn[iMarker] != NULL) delete [] TangGridVelIn[iMarker];
5283  delete [] TangGridVelIn;
5284  }
5285  if (SpanAreaIn != NULL) {
5286  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5287  if (SpanAreaIn[iMarker] != NULL) delete [] SpanAreaIn[iMarker];
5288  delete [] SpanAreaIn;
5289  }
5290  if (TurboRadiusIn != NULL) {
5291  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5292  if (TurboRadiusIn[iMarker] != NULL) delete [] TurboRadiusIn[iMarker];
5293  delete [] TurboRadiusIn;
5294  }
5295  if (TangGridVelOut != NULL) {
5296  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5297  if (TangGridVelOut[iMarker] != NULL) delete [] TangGridVelOut[iMarker];
5298  delete [] TangGridVelOut;
5299  }
5300  if (SpanAreaOut != NULL) {
5301  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5302  if (SpanAreaOut[iMarker] != NULL) delete [] SpanAreaOut[iMarker];
5303  delete [] SpanAreaOut;
5304  }
5305  if (TurboRadiusOut != NULL) {
5306  for (iMarker = 0; iMarker < nTurboPerf; iMarker++)
5307  if (TurboRadiusOut[iMarker] != NULL) delete [] TurboRadiusOut[iMarker];
5308  delete [] TurboRadiusOut;
5309  }
5310 
5311  /*--- Free up memory from turbomachinery computations
5312  * If there are send/receive boundaries, nMarker isn't the same number
5313  * as in the constructor. There must be an explicit check to ensure
5314  * that iMarker doesn't point us to memory that was never allocated. ---*/
5315 
5316  unsigned short iSpan, iVertex;
5317  if (turbovertex != NULL) {
5318  for (iMarker = 0; iMarker < nMarker; iMarker++) {
5319  if (Marker_All_SendRecv[iMarker] == 0 && turbovertex[iMarker] != NULL) {
5320  for (iSpan= 0; iSpan < nSpanSectionsByMarker[iMarker]; iSpan++) {
5321  if (turbovertex[iMarker][iSpan] != NULL) {
5322  for (iVertex = 0; iVertex < nVertexSpan[iMarker][iSpan]; iVertex++)
5323  if (turbovertex[iMarker][iSpan][iVertex] != NULL)
5324  delete turbovertex[iMarker][iSpan][iVertex];
5325  delete [] turbovertex[iMarker][iSpan];
5326  }
5327  }
5328  delete [] turbovertex[iMarker];
5329  }
5330  }
5331  delete [] turbovertex;
5332  }
5333  if (AverageTurboNormal != NULL) {
5334  for (iMarker = 0; iMarker < nMarker; iMarker++) {
5335  if (Marker_All_SendRecv[iMarker] == 0 && AverageTurboNormal[iMarker] != NULL) {
5336  for (iSpan= 0; iSpan < nSpanSectionsByMarker[iMarker]+1; iSpan++)
5337  delete [] AverageTurboNormal[iMarker][iSpan];
5338  delete [] AverageTurboNormal[iMarker];
5339  }
5340  }
5341  delete [] AverageTurboNormal;
5342  }
5343  if (AverageNormal != NULL) {
5344  for (iMarker = 0; iMarker < nMarker; iMarker++) {
5345  if (Marker_All_SendRecv[iMarker] == 0 && AverageNormal[iMarker] != NULL) {
5346  for (iSpan= 0; iSpan < nSpanSectionsByMarker[iMarker]+1; iSpan++)
5347  delete [] AverageNormal[iMarker][iSpan];
5348  delete [] AverageNormal[iMarker];
5349  }
5350  }
5351  delete [] AverageNormal;
5352  }
5353  if (AverageGridVel != NULL) {
5354  for (iMarker = 0; iMarker < nMarker; iMarker++) {
5355  if (Marker_All_SendRecv[iMarker] == 0 && AverageGridVel[iMarker] != NULL) {
5356  for (iSpan= 0; iSpan < nSpanSectionsByMarker[iMarker]+1; iSpan++)
5357  delete [] AverageGridVel[iMarker][iSpan];
5358  delete [] AverageGridVel[iMarker];
5359  }
5360  }
5361  delete [] AverageGridVel;
5362  }
5363 
5364  if (AverageTangGridVel != NULL) {
5365  for (iMarker = 0; iMarker < nMarker; iMarker++)
5366  if (Marker_All_SendRecv[iMarker] == 0 && AverageTangGridVel[iMarker] != NULL)
5367  delete [] AverageTangGridVel[iMarker];
5368  delete [] AverageTangGridVel;
5369  }
5370  if (SpanArea != NULL) {
5371  for (iMarker = 0; iMarker < nMarker; iMarker++)
5372  if (Marker_All_SendRecv[iMarker] == 0 && SpanArea[iMarker] != NULL)
5373  delete [] SpanArea[iMarker];
5374  delete [] SpanArea;
5375  }
5376  if (TurboRadius != NULL) {
5377  for (iMarker = 0; iMarker < nMarker; iMarker++)
5378  if (Marker_All_SendRecv[iMarker] == 0 && TurboRadius[iMarker] != NULL)
5379  delete [] TurboRadius[iMarker];
5380  delete [] TurboRadius;
5381  }
5382  if (MaxAngularCoord != NULL) {
5383  for (iMarker = 0; iMarker < nMarker; iMarker++)
5384  if (Marker_All_SendRecv[iMarker] == 0 && MaxAngularCoord[iMarker] != NULL)
5385  delete [] MaxAngularCoord[iMarker];
5386  delete [] MaxAngularCoord;
5387  }
5388  if (MinAngularCoord != NULL) {
5389  for (iMarker = 0; iMarker < nMarker; iMarker++)
5390  if (Marker_All_SendRecv[iMarker] == 0 && MinAngularCoord[iMarker] != NULL)
5391  delete [] MinAngularCoord[iMarker];
5392  delete [] MinAngularCoord;
5393  }
5394  if (MinRelAngularCoord != NULL) {
5395  for (iMarker = 0; iMarker < nMarker; iMarker++)
5396  if (Marker_All_SendRecv[iMarker] == 0 && MinRelAngularCoord[iMarker] != NULL)
5397  delete [] MinRelAngularCoord[iMarker];
5398  delete [] MinRelAngularCoord;
5399  }
5400 
5401  if (nSpanWiseSections != NULL) delete [] nSpanWiseSections;
5402  if (nSpanSectionsByMarker != NULL) delete [] nSpanSectionsByMarker;
5403  if (SpanWiseValue != NULL) {
5404  for (iMarker = 0; iMarker < 2; iMarker++)
5405  if (Marker_All_SendRecv[iMarker] == 0 && SpanWiseValue[iMarker] != NULL)
5406  delete [] SpanWiseValue[iMarker];
5407  delete [] SpanWiseValue;
5408  }
5409  if (nVertexSpan != NULL) {
5410  for (iMarker = 0; iMarker < nMarker; iMarker++)
5411  if (Marker_All_SendRecv[iMarker] == 0 && nVertexSpan[iMarker] != NULL)
5412  delete [] nVertexSpan[iMarker];
5413  delete [] nVertexSpan;
5414  }
5415  if (nTotVertexSpan != NULL) {
5416  for (iMarker = 0; iMarker < nMarker; iMarker++)
5417  if (Marker_All_SendRecv[iMarker] == 0 && nTotVertexSpan[iMarker] != NULL)
5418  delete [] nTotVertexSpan[iMarker];
5419  delete [] nTotVertexSpan;
5420  }
5421 
5422 }
5423 
5425  CGeometry *geometry) {
5426 
5427  /*--- To start, each linear partition carries the color only for the
5428  owned nodes (nPoint), but we have repeated elems on each linear partition.
5429  We need to complete the coloring information such that the repeated
5430  points on each rank also have their color values. ---*/
5431 
5432  unsigned short iNode, jNode;
5433  unsigned long iPoint, iNeighbor, jPoint, iElem, iProcessor;
5434 
5435  map<unsigned long, unsigned long> Point_Map;
5436  map<unsigned long, unsigned long>::iterator MI;
5437 
5438  vector<unsigned long>::iterator it;
5439 
5440  SU2_MPI::Request *colorSendReq = NULL, *idSendReq = NULL;
5441  SU2_MPI::Request *colorRecvReq = NULL, *idRecvReq = NULL;
5442  int iProc, iSend, iRecv, myStart, myFinal;
5443 
5444  /*--- First, create a complete map of the points on this rank (excluding
5445  repeats) and their neighbors so that we can efficiently loop through the
5446  points and decide how to distribute the colors. ---*/
5447 
5448  for (iElem = 0; iElem < geometry->GetnElem(); iElem++) {
5449  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
5450  iPoint = geometry->elem[iElem]->GetNode(iNode);
5451  Point_Map[iPoint] = iPoint;
5452  }
5453  }
5454 
5455  /*--- Error check to ensure that the number of points found for this
5456  rank matches the number in the mesh file (in serial). ---*/
5457 
5458  if ((size == SINGLE_NODE) && (Point_Map.size() < geometry->GetnPoint())) {
5459  SU2_MPI::Error( string("Mismatch between NPOIN and number of points")
5460  +string(" listed in mesh file.\n")
5461  +string("Please check the mesh file for correctness.\n"),
5463  }
5464 
5465  /*--- Create a global to local mapping that includes the unowned points. ---*/
5466 
5467  map<unsigned long, unsigned long> Global2Local;
5468  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) {
5469  Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint;
5470  }
5471 
5472  /*--- Find extra points that carry an index higher than nPoint. ---*/
5473 
5474  jPoint = geometry->GetnPoint();
5475  for (MI = Point_Map.begin(); MI != Point_Map.end(); MI++) {
5476  iPoint = MI->first;
5477  if ((Point_Map[iPoint] < geometry->starting_node[rank]) ||
5478  (Point_Map[iPoint] >= geometry->ending_node[rank])){
5479  Global2Local[Point_Map[iPoint]] = jPoint;
5480  jPoint++;
5481  }
5482  }
5483 
5484  /*--- Now create the neighbor list for each owned node (self-inclusive). ---*/
5485 
5486  Neighbors.clear();
5487  Neighbors.resize(Point_Map.size());
5488  for (iElem = 0; iElem < geometry->GetnElem(); iElem++) {
5489  for (iNode = 0; iNode < geometry->elem[iElem]->GetnNodes(); iNode++) {
5490  iPoint = Global2Local[geometry->elem[iElem]->GetNode(iNode)];
5491  for (jNode = 0; jNode < geometry->elem[iElem]->GetnNodes(); jNode++) {
5492  jPoint = geometry->elem[iElem]->GetNode(jNode);
5493  Neighbors[iPoint].push_back(jPoint);
5494  }
5495  }
5496  }
5497 
5498  /*--- Post-process the neighbor lists. ---*/
5499 
5500  for (iPoint = 0; iPoint < Point_Map.size(); iPoint++) {
5501  sort(Neighbors[iPoint].begin(), Neighbors[iPoint].end());
5502  it = unique(Neighbors[iPoint].begin(), Neighbors[iPoint].end());
5503  Neighbors[iPoint].resize(it - Neighbors[iPoint].begin());
5504  }
5505 
5506  /*--- Prepare structures for communication. ---*/
5507 
5508  int *nPoint_Send = new int[size+1]; nPoint_Send[0] = 0;
5509  int *nPoint_Recv = new int[size+1]; nPoint_Recv[0] = 0;
5510  int *nPoint_Flag = new int[size];
5511 
5512  for (iProc = 0; iProc < size; iProc++) {
5513  nPoint_Send[iProc] = 0; nPoint_Recv[iProc] = 0; nPoint_Flag[iProc]= -1;
5514  }
5515  nPoint_Send[size] = 0; nPoint_Recv[size] = 0;
5516 
5517  /*--- Loop over the owned points and check all the neighbors for unowned
5518  points. The colors of all owned points will be communicated to any ranks
5519  that will require them, which is due to the repeated points/elements
5520  that were needed to perform the coloring. ---*/
5521 
5522  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) {
5523  for (iNeighbor = 0; iNeighbor < Neighbors[iPoint].size(); iNeighbor++) {
5524 
5525  /*--- Global ID of the neighbor ---*/
5526 
5527  jPoint = Neighbors[iPoint][iNeighbor];
5528 
5529  /*--- Search for the processor that owns this neighbor. ---*/
5530 
5531  iProcessor = jPoint/geometry->npoint_procs[0];
5532  if (iProcessor >= (unsigned long)size)
5533  iProcessor = (unsigned long)size-1;
5534  if (jPoint >= geometry->nPoint_Linear[iProcessor])
5535  while(jPoint >= geometry->nPoint_Linear[iProcessor+1]) iProcessor++;
5536  else
5537  while(jPoint < geometry->nPoint_Linear[iProcessor]) iProcessor--;
5538 
5539  /*--- If we have not visited this node yet, increment our
5540  number of points that must be sent to a particular proc. ---*/
5541 
5542  if (nPoint_Flag[iProcessor] != (int)iPoint) {
5543  nPoint_Flag[iProcessor] = (int)iPoint;
5544  nPoint_Send[iProcessor+1]++;
5545  }
5546 
5547  }
5548  }
5549 
5550  /*--- Communicate the number of nodes to be sent/recv'd amongst
5551  all processors. After this communication, each proc knows how
5552  many points it will receive from each other processor. ---*/
5553 
5554  SU2_MPI::Alltoall(&(nPoint_Send[1]), 1, MPI_INT,
5555  &(nPoint_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD);
5556 
5557  /*--- Prepare to send colors. First check how many
5558  messages we will be sending and receiving. Here we also put
5559  the counters into cumulative storage format to make the
5560  communications simpler. ---*/
5561 
5562  int nSends = 0, nRecvs = 0;
5563  for (iProc = 0; iProc < size; iProc++) nPoint_Flag[iProc] = -1;
5564 
5565  for (iProc = 0; iProc < size; iProc++) {
5566  if ((iProc != rank) && (nPoint_Send[iProc+1] > 0)) nSends++;
5567  if ((iProc != rank) && (nPoint_Recv[iProc+1] > 0)) nRecvs++;
5568 
5569  nPoint_Send[iProc+1] += nPoint_Send[iProc];
5570  nPoint_Recv[iProc+1] += nPoint_Recv[iProc];
5571  }
5572 
5573  /*--- Allocate arrays for sending the global ID. ---*/
5574 
5575  unsigned long *idSend = new unsigned long[nPoint_Send[size]];
5576  for (iSend = 0; iSend < nPoint_Send[size]; iSend++) idSend[iSend] = 0;
5577 
5578  /*--- Allocate memory to hold the colors that we are sending. ---*/
5579 
5580  unsigned long *colorSend = new unsigned long[nPoint_Send[size]];
5581  for (iSend = 0; iSend < nPoint_Send[size]; iSend++) colorSend[iSend] = 0;
5582 
5583  /*--- Create an index variable to keep track of our index
5584  positions as we load up the send buffer. ---*/
5585 
5586  unsigned long *index = new unsigned long[size];
5587  for (iProc = 0; iProc < size; iProc++) index[iProc] = nPoint_Send[iProc];
5588 
5589  /*--- Now load up our buffers with the Global IDs and colors. ---*/
5590 
5591  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) {
5592  for (iNeighbor = 0; iNeighbor < Neighbors[iPoint].size(); iNeighbor++) {
5593 
5594  /*--- Global ID of the neighbor ---*/
5595 
5596  jPoint = Neighbors[iPoint][iNeighbor];
5597 
5598  /*--- Search for the processor that owns this neighbor ---*/
5599 
5600  iProcessor = jPoint/geometry->npoint_procs[0];
5601  if (iProcessor >= (unsigned long)size)
5602  iProcessor = (unsigned long)size-1;
5603  if (jPoint >= geometry->nPoint_Linear[iProcessor])
5604  while(jPoint >= geometry->nPoint_Linear[iProcessor+1]) iProcessor++;
5605  else
5606  while(jPoint < geometry->nPoint_Linear[iProcessor]) iProcessor--;
5607 
5608  /*--- If we have not visited this node yet, increment our
5609  counters and load up the global ID and color. ---*/
5610 
5611  if (nPoint_Flag[iProcessor] != (int)iPoint) {
5612 
5613  nPoint_Flag[iProcessor] = (int)iPoint;
5614  unsigned long nn = index[iProcessor];
5615 
5616  /*--- Load the data values. ---*/
5617 
5618  idSend[nn] = geometry->node[iPoint]->GetGlobalIndex();
5619  colorSend[nn] = geometry->node[iPoint]->GetColor();
5620 
5621  /*--- Increment the index by the message length ---*/
5622 
5623  index[iProcessor]++;
5624 
5625  }
5626  }
5627  }
5628 
5629  /*--- Free memory after loading up the send buffer. ---*/
5630 
5631  delete [] index;
5632 
5633  /*--- Allocate the memory that we need for receiving the conn
5634  values and then cue up the non-blocking receives. Note that
5635  we do not include our own rank in the communications. We will
5636  directly copy our own data later. ---*/
5637 
5638  unsigned long *colorRecv = new unsigned long[nPoint_Recv[size]];
5639  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++)
5640  colorRecv[iRecv] = 0;
5641 
5642  unsigned long *idRecv = new unsigned long[nPoint_Recv[size]];
5643  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++)
5644  idRecv[iRecv] = 0;
5645 
5646  /*--- Allocate memory for the MPI requests if we need to communicate. ---*/
5647 
5648  if (nSends > 0) {
5649  colorSendReq = new SU2_MPI::Request[nSends];
5650  idSendReq = new SU2_MPI::Request[nSends];
5651  }
5652  if (nRecvs > 0) {
5653  colorRecvReq = new SU2_MPI::Request[nRecvs];
5654  idRecvReq = new SU2_MPI::Request[nRecvs];
5655  }
5656 
5657  /*--- Launch the non-blocking sends and receives. ---*/
5658 
5659  InitiateComms(colorSend, nPoint_Send, colorSendReq,
5660  colorRecv, nPoint_Recv, colorRecvReq,
5662 
5663  InitiateComms(idSend, nPoint_Send, idSendReq,
5664  idRecv, nPoint_Recv, idRecvReq,
5666 
5667  /*--- Copy my own rank's data into the recv buffer directly. ---*/
5668 
5669  iRecv = nPoint_Recv[rank];
5670  myStart = nPoint_Send[rank];
5671  myFinal = nPoint_Send[rank+1];
5672  for (iSend = myStart; iSend < myFinal; iSend++) {
5673  colorRecv[iRecv] = colorSend[iSend];
5674  idRecv[iRecv] = idSend[iSend];
5675  iRecv++;
5676  }
5677 
5678  /*--- Complete the non-blocking communications. ---*/
5679 
5680  CompleteComms(nSends, colorSendReq, nRecvs, colorRecvReq);
5681  CompleteComms(nSends, idSendReq, nRecvs, idRecvReq);
5682 
5683  /*--- Store the complete color map for this rank in class data. Now,
5684  each rank has a color value for all owned nodes as well as any repeated
5685  grid points on the rank. Note that there may be repeats that are
5686  communicated in the routine above, but since we are storing in a map,
5687  it will simply overwrite the same entries. ---*/
5688 
5689  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++) {
5690  Color_List[idRecv[iRecv]] = colorRecv[iRecv];
5691  }
5692 
5693  /*--- Free temporary memory from communications ---*/
5694 
5695  if (colorSendReq != NULL) delete [] colorSendReq;
5696  if (idSendReq != NULL) delete [] idSendReq;
5697 
5698  if (colorRecvReq != NULL) delete [] colorRecvReq;
5699  if (idRecvReq != NULL) delete [] idRecvReq;
5700 
5701  delete [] colorSend;
5702  delete [] colorRecv;
5703  delete [] idSend;
5704  delete [] idRecv;
5705  delete [] nPoint_Recv;
5706  delete [] nPoint_Send;
5707  delete [] nPoint_Flag;
5708 
5709 }
5710 
5712  CGeometry *geometry,
5713  unsigned short Elem_Type) {
5714 
5715  unsigned short NODES_PER_ELEMENT = 0;
5716 
5717  unsigned long iProcessor;
5718  unsigned long iElem, iNode, jNode, nElem_Total = 0, Global_Index;
5719  unsigned long *Conn_Elem = NULL;
5720  unsigned long *ID_Elems = NULL;
5721 
5722  SU2_MPI::Request *connSendReq = NULL, *idSendReq = NULL;
5723  SU2_MPI::Request *connRecvReq = NULL, *idRecvReq = NULL;
5724  int iProc, iSend, iRecv, myStart, myFinal;
5725 
5726  /*--- Store the number of nodes per this element type. ---*/
5727 
5728  switch (Elem_Type) {
5729  case TRIANGLE:
5730  NODES_PER_ELEMENT = N_POINTS_TRIANGLE;
5731  break;
5732  case QUADRILATERAL:
5733  NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL;
5734  break;
5735  case TETRAHEDRON:
5736  NODES_PER_ELEMENT = N_POINTS_TETRAHEDRON;
5737  break;
5738  case HEXAHEDRON:
5739  NODES_PER_ELEMENT = N_POINTS_HEXAHEDRON;
5740  break;
5741  case PRISM:
5742  NODES_PER_ELEMENT = N_POINTS_PRISM;
5743  break;
5744  case PYRAMID:
5745  NODES_PER_ELEMENT = N_POINTS_PYRAMID;
5746  break;
5747  default:
5748  NODES_PER_ELEMENT = 0;
5749  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
5750  break;
5751  }
5752 
5753  /*--- Prepare a mapping for local to global element index. ---*/
5754 
5755  map<unsigned long, unsigned long> Local2GlobalElem;
5756  map<unsigned long, unsigned long>::iterator MI;
5757 
5758  for (MI = geometry->Global_to_Local_Elem.begin();
5759  MI != geometry->Global_to_Local_Elem.end(); MI++) {
5760  Local2GlobalElem[MI->second] = MI->first;
5761  }
5762 
5763  /*--- We start with the connectivity distributed across all procs in a
5764  linear partitioning. We need to loop through our local partition
5765  and decide how many elements we must send to each other rank in order to
5766  have all elements distributed according to the ParMETIS coloring. ---*/
5767 
5768  int *nElem_Send = new int[size+1]; nElem_Send[0] = 0;
5769  int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0;
5770  int *nElem_Flag = new int[size];
5771 
5772  for (iProc = 0; iProc < size; iProc++) {
5773  nElem_Send[iProc] = 0; nElem_Recv[iProc] = 0; nElem_Flag[iProc]= -1;
5774  }
5775  nElem_Send[size] = 0; nElem_Recv[size] = 0;
5776 
5777  for (iElem = 0; iElem < geometry->GetnElem(); iElem++ ) {
5778  if (geometry->elem[iElem]->GetVTK_Type() == Elem_Type) {
5779  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++ ) {
5780 
5781  /*--- Get the index of the current point. ---*/
5782 
5783  Global_Index = geometry->elem[iElem]->GetNode(iNode);
5784 
5785  /*--- We have the color stored in a map for all local points. ---*/
5786 
5787  iProcessor = Color_List[Global_Index];
5788 
5789  /*--- If we have not visited this element yet, increment our
5790  number of elements that must be sent to a particular proc. ---*/
5791 
5792  if ((nElem_Flag[iProcessor] != (int)iElem)) {
5793  nElem_Flag[iProcessor] = (int)iElem;
5794  nElem_Send[iProcessor+1]++;
5795  }
5796 
5797  }
5798  }
5799  }
5800 
5801  /*--- Communicate the number of cells to be sent/recv'd amongst
5802  all processors. After this communication, each proc knows how
5803  many cells it will receive from each other processor. ---*/
5804 
5805  SU2_MPI::Alltoall(&(nElem_Send[1]), 1, MPI_INT,
5806  &(nElem_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD);
5807 
5808  /*--- Prepare to send connectivities. First check how many
5809  messages we will be sending and receiving. Here we also put
5810  the counters into cumulative storage format to make the
5811  communications simpler. ---*/
5812 
5813  int nSends = 0, nRecvs = 0;
5814  for (iProc = 0; iProc < size; iProc++) nElem_Flag[iProc] = -1;
5815 
5816  for (iProc = 0; iProc < size; iProc++) {
5817  if ((iProc != rank) && (nElem_Send[iProc+1] > 0)) nSends++;
5818  if ((iProc != rank) && (nElem_Recv[iProc+1] > 0)) nRecvs++;
5819 
5820  nElem_Send[iProc+1] += nElem_Send[iProc];
5821  nElem_Recv[iProc+1] += nElem_Recv[iProc];
5822  }
5823 
5824  /*--- Allocate memory to hold the connectivity and element IDs
5825  that we are sending. ---*/
5826 
5827  unsigned long *connSend = NULL;
5828  connSend = new unsigned long[NODES_PER_ELEMENT*nElem_Send[size]];
5829  for (iSend = 0; iSend < NODES_PER_ELEMENT*nElem_Send[size]; iSend++)
5830  connSend[iSend] = 0;
5831 
5832  /*--- Allocate arrays for storing element global index. ---*/
5833 
5834  unsigned long *idSend = new unsigned long[nElem_Send[size]];
5835  for (iSend = 0; iSend < nElem_Send[size]; iSend++) idSend[iSend] = 0;
5836 
5837  /*--- Create an index variable to keep track of our index
5838  position as we load up the send buffer. ---*/
5839 
5840  unsigned long *index = new unsigned long[size];
5841  for (iProc = 0; iProc < size; iProc++)
5842  index[iProc] = NODES_PER_ELEMENT*nElem_Send[iProc];
5843 
5844  unsigned long *idIndex = new unsigned long[size];
5845  for (iProc = 0; iProc < size; iProc++)
5846  idIndex[iProc] = nElem_Send[iProc];
5847 
5848  /*--- Loop through our elements and load the elems and their
5849  additional data that we will send to the other procs. ---*/
5850 
5851  for (iElem = 0; iElem < geometry->GetnElem(); iElem++) {
5852  if (geometry->elem[iElem]->GetVTK_Type() == Elem_Type) {
5853  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++ ) {
5854 
5855  /*--- Get the index of the current point. ---*/
5856 
5857  Global_Index = geometry->elem[iElem]->GetNode(iNode);
5858 
5859  /*--- We have the color stored in a map for all local points. ---*/
5860 
5861  iProcessor = Color_List[Global_Index];
5862 
5863  /*--- Load connectivity and IDs into the buffer for sending ---*/
5864 
5865  if (nElem_Flag[iProcessor] != (int)iElem) {
5866 
5867  nElem_Flag[iProcessor] = (int)iElem;
5868  unsigned long nn = index[iProcessor];
5869  unsigned long mm = idIndex[iProcessor];
5870 
5871  /*--- Load the connectivity values. Note that elements are already
5872  stored directly based on their global index for the nodes.---*/
5873 
5874  for (jNode = 0; jNode < NODES_PER_ELEMENT; jNode++) {
5875  connSend[nn] = geometry->elem[iElem]->GetNode(jNode); nn++;
5876  }
5877 
5878  /*--- Global ID for this element. ---*/
5879 
5880  idSend[mm] = Local2GlobalElem[iElem];
5881 
5882  /*--- Increment the index by the message length ---*/
5883 
5884  index[iProcessor] += NODES_PER_ELEMENT;
5885  idIndex[iProcessor]++;
5886 
5887  }
5888  }
5889  }
5890  }
5891 
5892  /*--- Free memory after loading up the send buffer. ---*/
5893 
5894  delete [] index;
5895  delete [] idIndex;
5896 
5897  /*--- Allocate the memory that we need for receiving the
5898  values and then cue up the non-blocking receives. Note that
5899  we do not include our own rank in the communications. We will
5900  directly copy our own data later. ---*/
5901 
5902  unsigned long *connRecv = NULL;
5903  connRecv = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
5904  for (iRecv = 0; iRecv < NODES_PER_ELEMENT*nElem_Recv[size]; iRecv++)
5905  connRecv[iRecv] = 0;
5906 
5907  unsigned long *idRecv = new unsigned long[nElem_Recv[size]];
5908  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) idRecv[iRecv] = 0;
5909 
5910  /*--- Allocate memory for the MPI requests if we need to communicate. ---*/
5911 
5912  if (nSends > 0) {
5913  connSendReq = new SU2_MPI::Request[nSends];
5914  idSendReq = new SU2_MPI::Request[nSends];
5915  }
5916  if (nRecvs > 0) {
5917  connRecvReq = new SU2_MPI::Request[nRecvs];
5918  idRecvReq = new SU2_MPI::Request[nRecvs];
5919  }
5920 
5921  /*--- Launch the non-blocking sends and receives. ---*/
5922 
5923  InitiateComms(connSend, nElem_Send, connSendReq,
5924  connRecv, nElem_Recv, connRecvReq,
5925  NODES_PER_ELEMENT, COMM_TYPE_UNSIGNED_LONG);
5926 
5927  InitiateComms(idSend, nElem_Send, idSendReq,
5928  idRecv, nElem_Recv, idRecvReq,
5930 
5931  /*--- Copy my own rank's data into the recv buffer directly. ---*/
5932 
5933  iRecv = NODES_PER_ELEMENT*nElem_Recv[rank];
5934  myStart = NODES_PER_ELEMENT*nElem_Send[rank];
5935  myFinal = NODES_PER_ELEMENT*nElem_Send[rank+1];
5936  for (iSend = myStart; iSend < myFinal; iSend++) {
5937  connRecv[iRecv] = connSend[iSend];
5938  iRecv++;
5939  }
5940 
5941  iRecv = nElem_Recv[rank];
5942  myStart = nElem_Send[rank];
5943  myFinal = nElem_Send[rank+1];
5944  for (iSend = myStart; iSend < myFinal; iSend++) {
5945  idRecv[iRecv] = idSend[iSend];
5946  iRecv++;
5947  }
5948 
5949  /*--- Complete the non-blocking communications. ---*/
5950 
5951  CompleteComms(nSends, connSendReq, nRecvs, connRecvReq);
5952  CompleteComms(nSends, idSendReq, nRecvs, idRecvReq);
5953 
5954  /*--- Store the connectivity for this rank in the proper structure
5955  It will be loaded into the geometry objects in a later step. ---*/
5956 
5957  if (nElem_Recv[size] > 0) {
5958  Conn_Elem = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
5959  int count = 0; nElem_Total = 0;
5960  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
5961  nElem_Total++;
5962  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
5963  Conn_Elem[count] = connRecv[iRecv*NODES_PER_ELEMENT+iNode];
5964  count++;
5965  }
5966  }
5967  }
5968 
5969  /*--- Store the global element IDs too. ---*/
5970 
5971  if (nElem_Recv[size] > 0) {
5972  ID_Elems = new unsigned long[nElem_Recv[size]];
5973  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
5974  ID_Elems[iRecv] = idRecv[iRecv];
5975  }
5976  }
5977 
5978  /*--- Store the particular element count, IDs, & conn. in the class data,
5979  and set the class data pointer to the connectivity array. ---*/
5980 
5981  switch (Elem_Type) {
5982  case TRIANGLE:
5983  nLocal_Tria = nElem_Total;
5984  if (nLocal_Tria > 0) {
5985  Conn_Tria = Conn_Elem;
5986  ID_Tria = ID_Elems;
5987  }
5988  break;
5989  case QUADRILATERAL:
5990  nLocal_Quad = nElem_Total;
5991  if (nLocal_Quad > 0) {
5992  Conn_Quad = Conn_Elem;
5993  ID_Quad = ID_Elems;
5994  }
5995  break;
5996  case TETRAHEDRON:
5997  nLocal_Tetr = nElem_Total;
5998  if (nLocal_Tetr > 0) {
5999  Conn_Tetr = Conn_Elem;
6000  ID_Tetr = ID_Elems;
6001  }
6002  break;
6003  case HEXAHEDRON:
6004  nLocal_Hexa = nElem_Total;
6005  if (nLocal_Hexa > 0) {
6006  Conn_Hexa = Conn_Elem;
6007  ID_Hexa = ID_Elems;
6008  }
6009  break;
6010  case PRISM:
6011  nLocal_Pris = nElem_Total;
6012  if (nLocal_Pris > 0) {
6013  Conn_Pris = Conn_Elem;
6014  ID_Pris = ID_Elems;
6015  }
6016  break;
6017  case PYRAMID:
6018  nLocal_Pyra = nElem_Total;
6019  if (nLocal_Pyra > 0) {
6020  Conn_Pyra = Conn_Elem;
6021  ID_Pyra = ID_Elems;
6022  }
6023  break;
6024  default:
6025  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
6026  break;
6027  }
6028 
6029  /*--- Free temporary memory from communications ---*/
6030 
6031  Local2GlobalElem.clear();
6032 
6033  if (connSendReq != NULL) delete [] connSendReq;
6034  if (idSendReq != NULL) delete [] idSendReq;
6035 
6036  if (connRecvReq != NULL) delete [] connRecvReq;
6037  if (idRecvReq != NULL) delete [] idRecvReq;
6038 
6039  delete [] connSend;
6040  delete [] connRecv;
6041  delete [] idSend;
6042  delete [] idRecv;
6043  delete [] nElem_Recv;
6044  delete [] nElem_Send;
6045  delete [] nElem_Flag;
6046 
6047 }
6048 
6050 
6051  /*--- We now know all of the coloring for our local points and neighbors.
6052  From this, we can communicate the owned nodes in our linear partitioning
6053  to all other ranks, including coordinates and coloring info, so that the
6054  receivers will be able to sort the data. ---*/
6055 
6056  unsigned short iDim;
6057  unsigned long iPoint, iNeighbor, jPoint, iProcessor;
6058  vector<unsigned long>::iterator it;
6059 
6060  SU2_MPI::Request *colorSendReq = NULL, *idSendReq = NULL, *coordSendReq = NULL;
6061  SU2_MPI::Request *colorRecvReq = NULL, *idRecvReq = NULL, *coordRecvReq = NULL;
6062  int iProc, iSend, iRecv, myStart, myFinal;
6063 
6064  /*--- Prepare structures for communication. ---*/
6065 
6066  int *nPoint_Send = new int[size+1]; nPoint_Send[0] = 0;
6067  int *nPoint_Recv = new int[size+1]; nPoint_Recv[0] = 0;
6068  int *nPoint_Flag = new int[size];
6069 
6070  for (iProc = 0; iProc < size; iProc++) {
6071  nPoint_Send[iProc] = 0; nPoint_Recv[iProc] = 0; nPoint_Flag[iProc]= -1;
6072  }
6073  nPoint_Send[size] = 0; nPoint_Recv[size] = 0;
6074 
6075  /*--- Loop over the owned points and check all the neighbors for unowned
6076  points. The colors of all owned points will be communicated to any ranks
6077  that will require them, which is due to the repeated points/elements
6078  that were needed to perform the coloring. ---*/
6079 
6080  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) {
6081  for (iNeighbor = 0; iNeighbor < Neighbors[iPoint].size(); iNeighbor++) {
6082 
6083  /*--- Global ID of the neighbor ---*/
6084 
6085  jPoint = Neighbors[iPoint][iNeighbor];
6086 
6087  /*--- We have the color stored in a map for all local points. ---*/
6088 
6089  iProcessor = Color_List[jPoint];
6090 
6091  /*--- If we have not visited this node yet, increment our
6092  number of points that must be sent to a particular proc. ---*/
6093 
6094  if (nPoint_Flag[iProcessor] != (int)iPoint) {
6095  nPoint_Flag[iProcessor] = (int)iPoint;
6096  nPoint_Send[iProcessor+1]++;
6097  }
6098  }
6099  }
6100 
6101  /*--- Communicate the number of nodes to be sent/recv'd amongst
6102  all processors. After this communication, each proc knows how
6103  many points it will receive from each other processor. ---*/
6104 
6105  SU2_MPI::Alltoall(&(nPoint_Send[1]), 1, MPI_INT,
6106  &(nPoint_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD);
6107 
6108  /*--- Prepare to send colors, ids, and coords. First check how many
6109  messages we will be sending and receiving. Here we also put
6110  the counters into cumulative storage format to make the
6111  communications simpler. ---*/
6112 
6113  int nSends = 0, nRecvs = 0;
6114  for (iProc = 0; iProc < size; iProc++) nPoint_Flag[iProc] = -1;
6115 
6116  for (iProc = 0; iProc < size; iProc++) {
6117  if ((iProc != rank) && (nPoint_Send[iProc+1] > 0)) nSends++;
6118  if ((iProc != rank) && (nPoint_Recv[iProc+1] > 0)) nRecvs++;
6119 
6120  nPoint_Send[iProc+1] += nPoint_Send[iProc];
6121  nPoint_Recv[iProc+1] += nPoint_Recv[iProc];
6122  }
6123 
6124  /*--- Allocate arrays for sending the global ID. ---*/
6125 
6126  unsigned long *idSend = new unsigned long[nPoint_Send[size]];
6127  for (iSend = 0; iSend < nPoint_Send[size]; iSend++) idSend[iSend] = 0;
6128 
6129  /*--- Allocate memory to hold the colors that we are sending. ---*/
6130 
6131  unsigned long *colorSend = new unsigned long[nPoint_Send[size]];
6132  for (iSend = 0; iSend < nPoint_Send[size]; iSend++) colorSend[iSend] = 0;
6133 
6134  /*--- Allocate memory to hold the coordinates that we are sending. ---*/
6135 
6136  su2double *coordSend = NULL;
6137  coordSend = new su2double[nDim*nPoint_Send[size]];
6138  for (iSend = 0; iSend < nDim*nPoint_Send[size]; iSend++)
6139  coordSend[iSend] = 0;
6140 
6141  /*--- Create index variables to keep track of our index
6142  positions as we load up the send buffer. ---*/
6143 
6144  unsigned long *index = new unsigned long[size];
6145  for (iProc = 0; iProc < size; iProc++)
6146  index[iProc] = nPoint_Send[iProc];
6147 
6148  unsigned long *coordIndex = new unsigned long[size];
6149  for (iProc = 0; iProc < size; iProc++)
6150  coordIndex[iProc] = nDim*nPoint_Send[iProc];
6151 
6152  /*--- Now load up our buffers with the colors, ids, and coords. ---*/
6153 
6154  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) {
6155  for (iNeighbor = 0; iNeighbor < Neighbors[iPoint].size(); iNeighbor++) {
6156 
6157  /*--- Global ID of the neighbor ---*/
6158 
6159  jPoint = Neighbors[iPoint][iNeighbor];
6160 
6161  /*--- We have the color stored in a map for all local points. ---*/
6162 
6163  iProcessor = Color_List[jPoint];
6164 
6165  /*--- If we have not visited this node yet, increment our
6166  counters and load up the colors, ids, and coords. ---*/
6167 
6168  if (nPoint_Flag[iProcessor] != (int)iPoint) {
6169 
6170  nPoint_Flag[iProcessor] = (int)iPoint;
6171  unsigned long nn = index[iProcessor];
6172 
6173  /*--- Load the global ID, color, and coordinate values. ---*/
6174 
6175  idSend[nn] = geometry->node[iPoint]->GetGlobalIndex();
6176  colorSend[nn] = geometry->node[iPoint]->GetColor();
6177 
6178  nn = coordIndex[iProcessor];
6179  for (iDim = 0; iDim < nDim; iDim++) {
6180  coordSend[nn] = geometry->node[iPoint]->GetCoord(iDim); nn++;
6181  }
6182 
6183  /*--- Increment the index by the message length ---*/
6184 
6185  coordIndex[iProcessor] += nDim;
6186  index[iProcessor]++;
6187 
6188  }
6189  }
6190  }
6191 
6192  /*--- Free memory after loading up the send buffer. ---*/
6193 
6194  delete [] index;
6195  delete [] coordIndex;
6196 
6197  /*--- Allocate the memory that we need for receiving the
6198  values and then cue up the non-blocking receives. Note that
6199  we do not include our own rank in the communications. We will
6200  directly copy our own data later. ---*/
6201 
6202  unsigned long *colorRecv = new unsigned long[nPoint_Recv[size]];
6203  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++)
6204  colorRecv[iRecv] = 0;
6205 
6206  unsigned long *idRecv = new unsigned long[nPoint_Recv[size]];
6207  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++)
6208  idRecv[iRecv] = 0;
6209 
6210  su2double *coordRecv = NULL;
6211  coordRecv = new su2double[nDim*nPoint_Recv[size]];
6212  for (iRecv = 0; iRecv < nDim*nPoint_Recv[size]; iRecv++)
6213  coordRecv[iRecv] = 0;
6214 
6215  /*--- Allocate memory for the MPI requests if we need to communicate. ---*/
6216 
6217  if (nSends > 0) {
6218  colorSendReq = new SU2_MPI::Request[nSends];
6219  idSendReq = new SU2_MPI::Request[nSends];
6220  coordSendReq = new SU2_MPI::Request[nSends];
6221 
6222  }
6223  if (nRecvs > 0) {
6224  colorRecvReq = new SU2_MPI::Request[nRecvs];
6225  idRecvReq = new SU2_MPI::Request[nRecvs];
6226  coordRecvReq = new SU2_MPI::Request[nRecvs];
6227  }
6228 
6229  /*--- Launch the non-blocking sends and receives. ---*/
6230 
6231  InitiateComms(colorSend, nPoint_Send, colorSendReq,
6232  colorRecv, nPoint_Recv, colorRecvReq,
6234 
6235  InitiateComms(idSend, nPoint_Send, idSendReq,
6236  idRecv, nPoint_Recv, idRecvReq,
6238 
6239  InitiateComms(coordSend, nPoint_Send, coordSendReq,
6240  coordRecv, nPoint_Recv, coordRecvReq,
6242 
6243  /*--- Copy my own rank's data into the recv buffer directly. ---*/
6244 
6245  iRecv = nPoint_Recv[rank];
6246  myStart = nPoint_Send[rank];
6247  myFinal = nPoint_Send[rank+1];
6248  for (iSend = myStart; iSend < myFinal; iSend++) {
6249  colorRecv[iRecv] = colorSend[iSend];
6250  idRecv[iRecv] = idSend[iSend];
6251  iRecv++;
6252  }
6253 
6254  iRecv = nDim*nPoint_Recv[rank];
6255  myStart = nDim*nPoint_Send[rank];
6256  myFinal = nDim*nPoint_Send[rank+1];
6257  for (iSend = myStart; iSend < myFinal; iSend++) {
6258  coordRecv[iRecv] = coordSend[iSend];
6259  iRecv++;
6260  }
6261 
6262  /*--- Complete the non-blocking communications. ---*/
6263 
6264  CompleteComms(nSends, colorSendReq, nRecvs, colorRecvReq);
6265  CompleteComms(nSends, idSendReq, nRecvs, idRecvReq);
6266  CompleteComms(nSends, coordSendReq, nRecvs, coordRecvReq);
6267 
6268  /*--- Store the total number of local points my rank has for
6269  the current section after completing the communications. ---*/
6270 
6271  nLocal_Point = nPoint_Recv[size];
6272 
6273  /*--- Store the proper local IDs, colors, and coordinates. We will load
6274  all of this information into our geometry classes in a later step. ---*/
6275 
6276  Local_Points = new unsigned long[nPoint_Recv[size]];
6277  Local_Colors = new unsigned long[nPoint_Recv[size]];
6278  Local_Coords = new su2double[nDim*nPoint_Recv[size]];
6279 
6280  nLocal_PointDomain = 0; nLocal_PointGhost = 0;
6281  for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++) {
6282  Local_Points[iRecv] = idRecv[iRecv];
6283  Local_Colors[iRecv] = colorRecv[iRecv];
6284  for (iDim = 0; iDim < nDim; iDim++)
6285  Local_Coords[iRecv*nDim+iDim] = coordRecv[iRecv*nDim+iDim];
6286  if (Local_Colors[iRecv] == (unsigned long)rank) nLocal_PointDomain++;
6287  else nLocal_PointGhost++;
6288  }
6289 
6290  /*--- Free temporary memory from communications ---*/
6291 
6292  if (colorSendReq != NULL) delete [] colorSendReq;
6293  if (idSendReq != NULL) delete [] idSendReq;
6294  if (coordSendReq != NULL) delete [] coordSendReq;
6295 
6296  if (colorRecvReq != NULL) delete [] colorRecvReq;
6297  if (idRecvReq != NULL) delete [] idRecvReq;
6298  if (coordRecvReq != NULL) delete [] coordRecvReq;
6299 
6300  delete [] colorSend;
6301  delete [] colorRecv;
6302  delete [] idSend;
6303  delete [] idRecv;
6304  delete [] coordSend;
6305  delete [] coordRecv;
6306  delete [] nPoint_Recv;
6307  delete [] nPoint_Send;
6308  delete [] nPoint_Flag;
6309 
6310 }
6311 
6313  CGeometry *geometry,
6314  unsigned short Elem_Type) {
6315 
6316  /*--- We begin with all marker information residing on the master rank,
6317  as the master currently stores all marker info when reading the grid.
6318  We first check and communicate basic information that each rank will
6319  need to hold its portion of the linearly partitioned markers. In a
6320  later step, we will distribute the markers according to the ParMETIS
6321  coloring. This intermediate step is necessary since we already have the
6322  correct coloring distributed by the linear partitions, which we would
6323  like to reuse when partitioning the markers. Plus, the markers should
6324  truly be linearly partitioned upon reading the mesh, which we will
6325  change eventually. ---*/
6326 
6327  unsigned short NODES_PER_ELEMENT = 0;
6328 
6329  unsigned long iMarker, iProcessor, iElem, iNode, jNode;
6330  unsigned long nElem_Total = 0, Global_Index, Global_Elem_Index;
6331 
6332  unsigned long *Conn_Elem = NULL;
6333  unsigned long *Linear_Markers = NULL;
6334  unsigned long *ID_SurfElem = NULL;
6335 
6336  SU2_MPI::Request *connSendReq = NULL, *markerSendReq = NULL, *idSendReq = NULL;
6337  SU2_MPI::Request *connRecvReq = NULL, *markerRecvReq = NULL, *idRecvReq = NULL;
6338  int iProc, iSend, iRecv, myStart, myFinal;
6339 
6340  /*--- Store the local number of this element type and the number of nodes
6341  per this element type. In serial, this will be the total number of this
6342  element type in the entire mesh. In parallel, it is the number on only
6343  the current partition. ---*/
6344 
6345  switch (Elem_Type) {
6346  case LINE:
6347  NODES_PER_ELEMENT = N_POINTS_LINE;
6348  break;
6349  case TRIANGLE:
6350  NODES_PER_ELEMENT = N_POINTS_TRIANGLE;
6351  break;
6352  case QUADRILATERAL:
6353  NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL;
6354  break;
6355  default:
6356  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
6357  break;
6358  }
6359 
6360  int *nElem_Send = new int[size+1]; nElem_Send[0] = 0;
6361  int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0;
6362  int *nElem_Flag = new int[size];
6363 
6364  for (iProc = 0; iProc < size; iProc++) {
6365  nElem_Send[iProc] = 0; nElem_Recv[iProc] = 0; nElem_Flag[iProc]= -1;
6366  }
6367  nElem_Send[size] = 0; nElem_Recv[size] = 0;
6368 
6369  /*--- We know that the master owns all of the info and will be the only
6370  rank sending anything, although all ranks might receive something. ---*/
6371 
6372  if (rank == MASTER_NODE) {
6373  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
6374 
6375  /*--- Reset the flag in between markers, just to ensure that we
6376  don't miss some elements on different markers with the same local
6377  index. ---*/
6378 
6379  for (iProc = 0; iProc < size; iProc++) nElem_Flag[iProc]= -1;
6380 
6381  for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) {
6382 
6383  if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) {
6384 
6385  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++ ) {
6386 
6387  /*--- Get the index of the current point (stored as global). ---*/
6388 
6389  Global_Index = geometry->bound[iMarker][iElem]->GetNode(iNode);
6390 
6391  /*--- Search for the processor that owns this point ---*/
6392 
6393  iProcessor = Global_Index/geometry->npoint_procs[0];
6394  if (iProcessor >= (unsigned long)size)
6395  iProcessor = (unsigned long)size-1;
6396  if (Global_Index >= geometry->nPoint_Linear[iProcessor])
6397  while(Global_Index >= geometry->nPoint_Linear[iProcessor+1])
6398  iProcessor++;
6399  else
6400  while(Global_Index < geometry->nPoint_Linear[iProcessor])
6401  iProcessor--;
6402 
6403  /*--- If we have not visited this element yet, increment our
6404  number of elements that must be sent to a particular proc. ---*/
6405 
6406  if ((nElem_Flag[iProcessor] != (int)iElem)) {
6407  nElem_Flag[iProcessor] = (int)iElem;
6408  nElem_Send[iProcessor+1]++;
6409  }
6410  }
6411  }
6412  }
6413  }
6414  }
6415 
6416  /*--- Communicate the number of cells to be sent/recv'd amongst
6417  all processors. After this communication, each proc knows how
6418  many cells it will receive from each other processor. ---*/
6419 
6420  SU2_MPI::Scatter(&(nElem_Send[1]), 1, MPI_INT,
6421  &(nElem_Recv[1]), 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD);
6422 
6423  /*--- Prepare to send connectivities. First check how many
6424  messages we will be sending and receiving. Here we also put
6425  the counters into cumulative storage format to make the
6426  communications simpler. ---*/
6427 
6428  int nSends = 0, nRecvs = 0;
6429  for (iProc = 0; iProc < size; iProc++) nElem_Flag[iProc] = -1;
6430 
6431  for (iProc = 0; iProc < size; iProc++) {
6432  if ((iProc != rank) && (nElem_Send[iProc+1] > 0)) nSends++;
6433  if ((iProc != rank) && (nElem_Recv[iProc+1] > 0)) nRecvs++;
6434 
6435  nElem_Send[iProc+1] += nElem_Send[iProc];
6436  nElem_Recv[iProc+1] += nElem_Recv[iProc];
6437  }
6438 
6439  /*--- Allocate memory to hold the connectivity that we are sending. ---*/
6440 
6441  unsigned long *connSend = NULL;
6442  unsigned long *markerSend = NULL;
6443  unsigned long *idSend = NULL;
6444 
6445  if (rank == MASTER_NODE) {
6446 
6447  connSend = new unsigned long[NODES_PER_ELEMENT*nElem_Send[size]];
6448  for (iSend = 0; iSend < NODES_PER_ELEMENT*nElem_Send[size]; iSend++)
6449  connSend[iSend] = 0;
6450 
6451  markerSend = new unsigned long[nElem_Send[size]];
6452  for (iSend = 0; iSend < nElem_Send[size]; iSend++)
6453  markerSend[iSend] = 0;
6454 
6455  idSend = new unsigned long[nElem_Send[size]];
6456  for (iSend = 0; iSend < nElem_Send[size]; iSend++)
6457  idSend[iSend] = 0;
6458 
6459  /*--- Create an index variable to keep track of our index
6460  position as we load up the send buffer. ---*/
6461 
6462  unsigned long *index = new unsigned long[size];
6463  for (iProc = 0; iProc < size; iProc++)
6464  index[iProc] = NODES_PER_ELEMENT*nElem_Send[iProc];
6465 
6466  unsigned long *markerIndex = new unsigned long[size];
6467  for (iProc = 0; iProc < size; iProc++)
6468  markerIndex[iProc] = nElem_Send[iProc];
6469 
6470  /*--- Loop through our elements and load the elems and their
6471  additional data that we will send to the other procs. ---*/
6472 
6473  Global_Elem_Index = 0;
6474  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
6475 
6476  /*--- Reset the flag in between markers, just to ensure that we
6477  don't miss some elements on different markers with the same local
6478  index. ---*/
6479 
6480  for (iProc = 0; iProc < size; iProc++) nElem_Flag[iProc]= -1;
6481 
6482  for (iElem = 0; iElem < geometry->GetnElem_Bound(iMarker); iElem++) {
6483  if (geometry->bound[iMarker][iElem]->GetVTK_Type() == Elem_Type) {
6484  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++ ) {
6485 
6486  /*--- Get the index of the current point. ---*/
6487 
6488  Global_Index = geometry->bound[iMarker][iElem]->GetNode(iNode);
6489 
6490  /*--- Search for the processor that owns this point ---*/
6491 
6492  iProcessor = Global_Index/geometry->npoint_procs[0];
6493  if (iProcessor >= (unsigned long)size)
6494  iProcessor = (unsigned long)size-1;
6495  if (Global_Index >= geometry->nPoint_Linear[iProcessor])
6496  while(Global_Index >= geometry->nPoint_Linear[iProcessor+1])
6497  iProcessor++;
6498  else
6499  while(Global_Index < geometry->nPoint_Linear[iProcessor])
6500  iProcessor--;
6501 
6502  /*--- Load connectivity into the buffer for sending ---*/
6503 
6504  if ((nElem_Flag[iProcessor] != (int)iElem)) {
6505 
6506  nElem_Flag[iProcessor] = (int)iElem;
6507  unsigned long nn = index[iProcessor];
6508  unsigned long mm = markerIndex[iProcessor];
6509 
6510  /*--- Load the connectivity values. ---*/
6511 
6512  for (jNode = 0; jNode < NODES_PER_ELEMENT; jNode++) {
6513  connSend[nn] = geometry->bound[iMarker][iElem]->GetNode(jNode);
6514  nn++;
6515  }
6516 
6517  /*--- Store the marker index and surface elem global ID ---*/
6518 
6519  markerSend[mm] = iMarker;
6520  idSend[mm] = Global_Elem_Index;
6521 
6522  /*--- Increment the index by the message length ---*/
6523 
6524  index[iProcessor] += NODES_PER_ELEMENT;
6525  markerIndex[iProcessor]++;
6526  }
6527 
6528  }
6529  }
6530 
6531  Global_Elem_Index++;
6532 
6533  }
6534  }
6535 
6536  /*--- Free memory after loading up the send buffer. ---*/
6537 
6538  delete [] index;
6539  delete [] markerIndex;
6540 
6541  }
6542 
6543  /*--- Allocate the memory that we need for receiving the conn
6544  values and then cue up the non-blocking receives. Note that
6545  we do not include our own rank in the communications. We will
6546  directly copy our own data later. ---*/
6547 
6548  unsigned long *connRecv = NULL;
6549  connRecv = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
6550  for (iRecv = 0; iRecv < NODES_PER_ELEMENT*nElem_Recv[size]; iRecv++)
6551  connRecv[iRecv] = 0;
6552 
6553  unsigned long *markerRecv = new unsigned long[nElem_Recv[size]];
6554  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++)
6555  markerRecv[iRecv] = 0;
6556 
6557  unsigned long *idRecv = new unsigned long[nElem_Recv[size]];
6558  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++)
6559  idRecv[iRecv] = 0;
6560 
6561  /*--- Allocate memory for the MPI requests if we need to communicate. ---*/
6562 
6563  if (nSends > 0) {
6564  connSendReq = new SU2_MPI::Request[nSends];
6565  markerSendReq = new SU2_MPI::Request[nSends];
6566  idSendReq = new SU2_MPI::Request[nSends];
6567  }
6568  if (nRecvs > 0) {
6569  connRecvReq = new SU2_MPI::Request[nRecvs];
6570  markerRecvReq = new SU2_MPI::Request[nRecvs];
6571  idRecvReq = new SU2_MPI::Request[nRecvs];
6572  }
6573 
6574  /*--- Launch the non-blocking sends and receives. ---*/
6575 
6576  InitiateComms(connSend, nElem_Send, connSendReq,
6577  connRecv, nElem_Recv, connRecvReq,
6578  NODES_PER_ELEMENT, COMM_TYPE_UNSIGNED_LONG);
6579 
6580  InitiateComms(markerSend, nElem_Send, markerSendReq,
6581  markerRecv, nElem_Recv, markerRecvReq,
6583 
6584  InitiateComms(idSend, nElem_Send, idSendReq,
6585  idRecv, nElem_Recv, idRecvReq,
6587 
6588  /*--- Copy my own rank's data into the recv buffer directly. ---*/
6589 
6590  if (rank == MASTER_NODE) {
6591 
6592  iRecv = NODES_PER_ELEMENT*nElem_Recv[rank];
6593  myStart = NODES_PER_ELEMENT*nElem_Send[rank];
6594  myFinal = NODES_PER_ELEMENT*nElem_Send[rank+1];
6595  for (iSend = myStart; iSend < myFinal; iSend++) {
6596  connRecv[iRecv] = connSend[iSend];
6597  iRecv++;
6598  }
6599 
6600  iRecv = nElem_Recv[rank];
6601  myStart = nElem_Send[rank];
6602  myFinal = nElem_Send[rank+1];
6603  for (iSend = myStart; iSend < myFinal; iSend++) {
6604  markerRecv[iRecv] = markerSend[iSend];
6605  idRecv[iRecv] = idSend[iSend];
6606  iRecv++;
6607  }
6608 
6609  }
6610 
6611  /*--- Complete the non-blocking communications. ---*/
6612 
6613  CompleteComms(nSends, connSendReq, nRecvs, connRecvReq);
6614  CompleteComms(nSends, markerSendReq, nRecvs, markerRecvReq);
6615  CompleteComms(nSends, idSendReq, nRecvs, idRecvReq);
6616 
6617  /*--- Store the connectivity for this rank in the proper data
6618  structure before post-processing below. First, allocate
6619  appropriate amount of memory for this section. ---*/
6620 
6621  if (nElem_Recv[size] > 0) {
6622  Conn_Elem = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
6623  int count = 0; nElem_Total = 0;
6624  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6625  nElem_Total++;
6626  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
6627  Conn_Elem[count] = connRecv[iRecv*NODES_PER_ELEMENT+iNode];
6628  count++;
6629  }
6630  }
6631  }
6632 
6633  /*--- Store the global marker ID for each element. ---*/
6634 
6635  if (nElem_Recv[size] > 0) {
6636  Linear_Markers = new unsigned long[nElem_Recv[size]];
6637  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6638  Linear_Markers[iRecv] = markerRecv[iRecv];
6639  }
6640  }
6641 
6642  /*--- Store the global surface elem ID for each element. ---*/
6643 
6644  if (nElem_Recv[size] > 0) {
6645  ID_SurfElem = new unsigned long[nElem_Recv[size]];
6646  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6647  ID_SurfElem[iRecv] = idRecv[iRecv];
6648  }
6649  }
6650 
6651  /*--- Store the particular global element count in the class data,
6652  and set the class data pointer to the connectivity array. ---*/
6653 
6654  switch (Elem_Type) {
6655  case LINE:
6656  nLinear_Line = nElem_Total;
6657  if (nLinear_Line > 0) {
6658  Conn_Line_Linear = Conn_Elem;
6659  ID_Line_Linear = Linear_Markers;
6660  Elem_ID_Line_Linear = ID_SurfElem;
6661  }
6662  break;
6663  case TRIANGLE:
6664  nLinear_BoundTria = nElem_Total;
6665  if (nLinear_BoundTria > 0) {
6666  Conn_BoundTria_Linear = Conn_Elem;
6667  ID_BoundTria_Linear = Linear_Markers;
6668  Elem_ID_BoundTria_Linear = ID_SurfElem;
6669  }
6670  break;
6671  case QUADRILATERAL:
6672  nLinear_BoundQuad = nElem_Total;
6673  if (nLinear_BoundQuad > 0) {
6674  Conn_BoundQuad_Linear = Conn_Elem;
6675  ID_BoundQuad_Linear = Linear_Markers;
6676  Elem_ID_BoundQuad_Linear = ID_SurfElem;
6677  }
6678  break;
6679  default:
6680  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
6681  break;
6682  }
6683 
6684  /*--- Free temporary memory from communications ---*/
6685 
6686  if (connSendReq != NULL) delete [] connSendReq;
6687  if (markerSendReq != NULL) delete [] markerSendReq;
6688  if (idSendReq != NULL) delete [] idSendReq;
6689 
6690  if (connRecvReq != NULL) delete [] connRecvReq;
6691  if (markerRecvReq != NULL) delete [] markerRecvReq;
6692  if (idRecvReq != NULL) delete [] idRecvReq;
6693 
6694  if (connSend != NULL) delete [] connSend;
6695  if (markerSend != NULL) delete [] markerSend;
6696  if (idSend != NULL) delete [] idSend;
6697 
6698  delete [] connRecv;
6699  delete [] markerRecv;
6700  delete [] idRecv;
6701 
6702  delete [] nElem_Recv;
6703  delete [] nElem_Send;
6704  delete [] nElem_Flag;
6705 
6706 }
6707 
6709  CGeometry *geometry,
6710  unsigned short Elem_Type) {
6711 
6712  unsigned short NODES_PER_ELEMENT = 0;
6713 
6714  unsigned long iProcessor, NELEM = 0;
6715  unsigned long iElem, iNode, jNode, nElem_Total = 0, Global_Index;
6716 
6717  unsigned long *Conn_Linear = NULL;
6718  unsigned long *Conn_Elem = NULL;
6719  unsigned long *Linear_Markers = NULL;
6720  unsigned long *ID_SurfElem_Linear = NULL;
6721  unsigned long *Local_Markers = NULL;
6722  unsigned long *ID_SurfElem = NULL;
6723 
6724  SU2_MPI::Request *connSendReq = NULL,*markerSendReq = NULL,*idSendReq = NULL;
6725  SU2_MPI::Request *connRecvReq = NULL,*markerRecvReq = NULL,*idRecvReq = NULL;
6726  int iProc, iSend, iRecv, myStart, myFinal;
6727 
6728  /*--- Store the local number of this element type and the number of nodes
6729  per this element type. In serial, this will be the total number of this
6730  element type in the entire mesh. In parallel, it is the number on only
6731  the current partition. ---*/
6732 
6733  switch (Elem_Type) {
6734  case LINE:
6735  NELEM = nLinear_Line;
6736  NODES_PER_ELEMENT = N_POINTS_LINE;
6737  Conn_Linear = Conn_Line_Linear;
6738  Linear_Markers = ID_Line_Linear;
6739  ID_SurfElem_Linear = Elem_ID_Line_Linear;
6740  break;
6741  case TRIANGLE:
6742  NELEM = nLinear_BoundTria;
6743  NODES_PER_ELEMENT = N_POINTS_TRIANGLE;
6744  Conn_Linear = Conn_BoundTria_Linear;
6745  Linear_Markers = ID_BoundTria_Linear;
6746  ID_SurfElem_Linear = Elem_ID_BoundTria_Linear;
6747  break;
6748  case QUADRILATERAL:
6749  NELEM = nLinear_BoundQuad;
6750  NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL;
6751  Conn_Linear = Conn_BoundQuad_Linear;
6752  Linear_Markers = ID_BoundQuad_Linear;
6753  ID_SurfElem_Linear = Elem_ID_BoundQuad_Linear;
6754  break;
6755  default:
6756  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
6757  break;
6758  }
6759 
6760  /*--- We start with the connectivity distributed across all procs in a
6761  linear partitioning. We need to loop through our local partition
6762  and decide how many elements we must send to each other rank in order to
6763  have all elements distributed according to the ParMETIS coloring. ---*/
6764 
6765  int *nElem_Send = new int[size+1]; nElem_Send[0] = 0;
6766  int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0;
6767  int *nElem_Flag = new int[size];
6768 
6769  for (iProc = 0; iProc < size; iProc++) {
6770  nElem_Send[iProc] = 0; nElem_Recv[iProc] = 0; nElem_Flag[iProc]= -1;
6771  }
6772  nElem_Send[size] = 0; nElem_Recv[size] = 0;
6773 
6774  for (iElem = 0; iElem < NELEM; iElem++) {
6775  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
6776 
6777  /*--- Get the index of the current point. ---*/
6778 
6779  Global_Index = Conn_Linear[iElem*NODES_PER_ELEMENT+iNode];
6780 
6781  /*--- We have the color stored in a map for all local points. ---*/
6782 
6783  iProcessor = Color_List[Global_Index];
6784 
6785  /*--- If we have not visited this element yet, increment our
6786  number of elements that must be sent to a particular proc. ---*/
6787 
6788  if ((nElem_Flag[iProcessor] != (int)iElem)) {
6789  nElem_Flag[iProcessor] = (int)iElem;
6790  nElem_Send[iProcessor+1]++;
6791  }
6792 
6793  }
6794  }
6795 
6796  /*--- Communicate the number of cells to be sent/recv'd amongst
6797  all processors. After this communication, each proc knows how
6798  many cells it will receive from each other processor. ---*/
6799 
6800  SU2_MPI::Alltoall(&(nElem_Send[1]), 1, MPI_INT,
6801  &(nElem_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD);
6802 
6803  /*--- Prepare to send connectivities. First check how many
6804  messages we will be sending and receiving. Here we also put
6805  the counters into cumulative storage format to make the
6806  communications simpler. ---*/
6807 
6808  int nSends = 0, nRecvs = 0;
6809  for (iProc = 0; iProc < size; iProc++) nElem_Flag[iProc] = -1;
6810 
6811  for (iProc = 0; iProc < size; iProc++) {
6812  if ((iProc != rank) && (nElem_Send[iProc+1] > 0)) nSends++;
6813  if ((iProc != rank) && (nElem_Recv[iProc+1] > 0)) nRecvs++;
6814 
6815  nElem_Send[iProc+1] += nElem_Send[iProc];
6816  nElem_Recv[iProc+1] += nElem_Recv[iProc];
6817  }
6818 
6819  /*--- Allocate memory to hold the connectivity that we are
6820  sending. ---*/
6821 
6822  unsigned long *connSend = NULL;
6823  connSend = new unsigned long[NODES_PER_ELEMENT*nElem_Send[size]];
6824  for (iSend = 0; iSend < NODES_PER_ELEMENT*nElem_Send[size]; iSend++)
6825  connSend[iSend] = 0;
6826 
6827  /*--- Allocate arrays for storing the marker global index. ---*/
6828 
6829  unsigned long *markerSend = new unsigned long[nElem_Send[size]];
6830  for (iSend = 0; iSend < nElem_Send[size]; iSend++) markerSend[iSend] = 0;
6831 
6832  unsigned long *idSend = new unsigned long[nElem_Send[size]];
6833  for (iSend = 0; iSend < nElem_Send[size]; iSend++) idSend[iSend] = 0;
6834 
6835  /*--- Create an index variable to keep track of our index
6836  position as we load up the send buffer. ---*/
6837 
6838  unsigned long *index = new unsigned long[size];
6839  for (iProc = 0; iProc < size; iProc++)
6840  index[iProc] = NODES_PER_ELEMENT*nElem_Send[iProc];
6841 
6842  unsigned long *markerIndex = new unsigned long[size];
6843  for (iProc = 0; iProc < size; iProc++)
6844  markerIndex[iProc] = nElem_Send[iProc];
6845 
6846  /*--- Loop through our elements and load the elems and their
6847  additional data that we will send to the other procs. ---*/
6848 
6849  for (iElem = 0; iElem < NELEM; iElem++) {
6850  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
6851 
6852  /*--- Get the index of the current point. ---*/
6853 
6854  Global_Index = Conn_Linear[iElem*NODES_PER_ELEMENT+iNode];
6855 
6856  /*--- We have the color stored in a map for all local points. ---*/
6857 
6858  iProcessor = Color_List[Global_Index];
6859 
6860  /*--- If we have not visited this element yet, load up the data
6861  for sending. ---*/
6862 
6863  if (nElem_Flag[iProcessor] != (int)iElem) {
6864 
6865  nElem_Flag[iProcessor] = (int)iElem;
6866  unsigned long nn = index[iProcessor];
6867  unsigned long mm = markerIndex[iProcessor];
6868 
6869  /*--- Load the connectivity values. ---*/
6870 
6871  for (jNode = 0; jNode < NODES_PER_ELEMENT; jNode++) {
6872 
6873  /*--- Note that elements are already stored directly based on
6874  their global index for the nodes. ---*/
6875 
6876  connSend[nn] = Conn_Linear[iElem*NODES_PER_ELEMENT+jNode]; nn++;
6877 
6878  }
6879 
6880  /*--- Global marker ID for this element. ---*/
6881 
6882  markerSend[mm] = Linear_Markers[iElem];
6883  idSend[mm] = ID_SurfElem_Linear[iElem];
6884 
6885  /*--- Increment the index by the message length ---*/
6886 
6887  index[iProcessor] += NODES_PER_ELEMENT;
6888  markerIndex[iProcessor]++;
6889 
6890  }
6891  }
6892  }
6893 
6894  /*--- Free memory after loading up the send buffer. ---*/
6895 
6896  delete [] index;
6897  delete [] markerIndex;
6898 
6899  /*--- Allocate the memory that we need for receiving the conn
6900  values and then cue up the non-blocking receives. Note that
6901  we do not include our own rank in the communications. We will
6902  directly copy our own data later. ---*/
6903 
6904  unsigned long *connRecv = NULL;
6905  connRecv = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
6906  for (iRecv = 0; iRecv < NODES_PER_ELEMENT*nElem_Recv[size]; iRecv++)
6907  connRecv[iRecv] = 0;
6908 
6909  unsigned long *markerRecv = new unsigned long[nElem_Recv[size]];
6910  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) markerRecv[iRecv] = 0;
6911 
6912  unsigned long *idRecv = new unsigned long[nElem_Recv[size]];
6913  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) idRecv[iRecv] = 0;
6914 
6915  /*--- Allocate memory for the MPI requests if we need to communicate. ---*/
6916 
6917  if (nSends > 0) {
6918  connSendReq = new SU2_MPI::Request[nSends];
6919  markerSendReq = new SU2_MPI::Request[nSends];
6920  idSendReq = new SU2_MPI::Request[nSends];
6921  }
6922  if (nRecvs > 0) {
6923  connRecvReq = new SU2_MPI::Request[nRecvs];
6924  markerRecvReq = new SU2_MPI::Request[nRecvs];
6925  idRecvReq = new SU2_MPI::Request[nRecvs];
6926  }
6927 
6928  /*--- Launch the non-blocking sends and receives. ---*/
6929 
6930  InitiateComms(connSend, nElem_Send, connSendReq,
6931  connRecv, nElem_Recv, connRecvReq,
6932  NODES_PER_ELEMENT, COMM_TYPE_UNSIGNED_LONG);
6933 
6934  InitiateComms(markerSend, nElem_Send, markerSendReq,
6935  markerRecv, nElem_Recv, markerRecvReq,
6937 
6938  InitiateComms(idSend, nElem_Send, idSendReq,
6939  idRecv, nElem_Recv, idRecvReq,
6941 
6942  /*--- Copy my own rank's data into the recv buffer directly. ---*/
6943 
6944  iRecv = NODES_PER_ELEMENT*nElem_Recv[rank];
6945  myStart = NODES_PER_ELEMENT*nElem_Send[rank];
6946  myFinal = NODES_PER_ELEMENT*nElem_Send[rank+1];
6947  for (iSend = myStart; iSend < myFinal; iSend++) {
6948  connRecv[iRecv] = connSend[iSend];
6949  iRecv++;
6950  }
6951 
6952  iRecv = nElem_Recv[rank];
6953  myStart = nElem_Send[rank];
6954  myFinal = nElem_Send[rank+1];
6955  for (iSend = myStart; iSend < myFinal; iSend++) {
6956  markerRecv[iRecv] = markerSend[iSend];
6957  idRecv[iRecv] = idSend[iSend];
6958  iRecv++;
6959  }
6960 
6961  /*--- Complete the non-blocking communications. ---*/
6962 
6963  CompleteComms(nSends, connSendReq, nRecvs, connRecvReq);
6964  CompleteComms(nSends, markerSendReq, nRecvs, markerRecvReq);
6965  CompleteComms(nSends, idSendReq, nRecvs, idRecvReq);
6966 
6967  /*--- Store the connectivity for this rank in the proper data
6968  structure. It will be loaded into the geometry objects in a later step. ---*/
6969 
6970  if (nElem_Recv[size] > 0) {
6971  Conn_Elem = new unsigned long[NODES_PER_ELEMENT*nElem_Recv[size]];
6972  int count = 0; nElem_Total = 0;
6973  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6974  nElem_Total++;
6975  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
6976  Conn_Elem[count] = connRecv[iRecv*NODES_PER_ELEMENT+iNode];
6977  count++;
6978  }
6979  }
6980  }
6981 
6982  /*--- Store the global marker IDs too. ---*/
6983 
6984  if (nElem_Recv[size] > 0) {
6985  Local_Markers = new unsigned long[nElem_Recv[size]];
6986  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6987  Local_Markers[iRecv] = markerRecv[iRecv];
6988  }
6989  }
6990 
6991  /*--- Store the global surface elem IDs too. ---*/
6992 
6993  if (nElem_Recv[size] > 0) {
6994  ID_SurfElem = new unsigned long[nElem_Recv[size]];
6995  for (iRecv = 0; iRecv < nElem_Recv[size]; iRecv++) {
6996  ID_SurfElem[iRecv] = idRecv[iRecv];
6997  }
6998  }
6999 
7000  /*--- Store the particular global element count in the class data,
7001  and set the class data pointer to the connectivity array. ---*/
7002 
7003  switch (Elem_Type) {
7004  case LINE:
7005  nLocal_Line = nElem_Total;
7006  if (nLocal_Line > 0) {
7007  Conn_Line = Conn_Elem;
7008  ID_Line = Local_Markers;
7009  Elem_ID_Line = ID_SurfElem;
7010  }
7011  break;
7012  case TRIANGLE:
7013  nLocal_BoundTria = nElem_Total;
7014  if (nLocal_BoundTria > 0) {
7015  Conn_BoundTria = Conn_Elem;
7016  ID_BoundTria = Local_Markers;
7017  Elem_ID_BoundTria = ID_SurfElem;
7018  }
7019  break;
7020  case QUADRILATERAL:
7021  nLocal_BoundQuad = nElem_Total;
7022  if (nLocal_BoundQuad > 0) {
7023  Conn_BoundQuad = Conn_Elem;
7024  ID_BoundQuad = Local_Markers;
7025  Elem_ID_BoundQuad = ID_SurfElem;
7026  }
7027  break;
7028  default:
7029  SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION);
7030  break;
7031  }
7032 
7033  /*--- Free temporary memory from communications ---*/
7034 
7035  if (connSendReq != NULL) delete [] connSendReq;
7036  if (markerSendReq != NULL) delete [] markerSendReq;
7037  if (idSendReq != NULL) delete [] idSendReq;
7038 
7039  if (connRecvReq != NULL) delete [] connRecvReq;
7040  if (markerRecvReq != NULL) delete [] markerRecvReq;
7041  if (idRecvReq != NULL) delete [] idRecvReq;
7042 
7043  delete [] connSend;
7044  delete [] connRecv;
7045  delete [] markerSend;
7046  delete [] markerRecv;
7047  delete [] idSend;
7048  delete [] idRecv;
7049  delete [] nElem_Recv;
7050  delete [] nElem_Send;
7051  delete [] nElem_Flag;
7052 
7053 }
7054 
7056 
7057  unsigned long iMarker, index, iChar;
7058 
7059  char str_buf[MAX_STRING_SIZE];
7060 
7061  /*--- The master node will communicate the entire list of marker tags
7062  (in global ordering) so that it will be simple for each rank to grab
7063  the string name for each marker. ---*/
7064 
7065  nMarker_Global = 0;
7066  if (rank == MASTER_NODE) nMarker_Global = config->GetnMarker_All();
7067 
7068  /*--- Broadcast the global number of markers in the mesh. ---*/
7069 
7070  SU2_MPI::Bcast(&nMarker_Global, 1, MPI_UNSIGNED_LONG,
7072 
7073  char *mpi_str_buf = new char[nMarker_Global*MAX_STRING_SIZE];
7074  if (rank == MASTER_NODE) {
7075  for (iMarker = 0; iMarker < nMarker_Global; iMarker++) {
7076  SPRINTF(&mpi_str_buf[iMarker*MAX_STRING_SIZE], "%s",
7077  config->GetMarker_All_TagBound(iMarker).c_str());
7078  }
7079  }
7080 
7081  /*--- Broadcast the string names of the variables. ---*/
7082 
7083  SU2_MPI::Bcast(mpi_str_buf, (int)nMarker_Global*MAX_STRING_SIZE, MPI_CHAR,
7085 
7086  /*--- Now parse the string names and load into our marker tag vector.
7087  We also need to set the values of all markers into the config. ---*/
7088 
7089  for (iMarker = 0; iMarker < nMarker_Global; iMarker++) {
7090  index = iMarker*MAX_STRING_SIZE;
7091  for (iChar = 0; iChar < MAX_STRING_SIZE; iChar++) {
7092  str_buf[iChar] = mpi_str_buf[index + iChar];
7093  }
7094  Marker_Tags.push_back(str_buf);
7095  config->SetMarker_All_TagBound(iMarker,str_buf);
7096  config->SetMarker_All_SendRecv(iMarker,NO);
7097  }
7098 
7099  /*--- Free string buffer memory. ---*/
7100 
7101  delete [] mpi_str_buf;
7102 
7103 }
7104 
7106 
7107  unsigned long iPoint, jPoint, iOwned, iPeriodic, iGhost;
7108 
7109  /*--- Create the basic point structures before storing the points. ---*/
7110 
7111  nPoint = nLocal_Point;
7112  nPointDomain = nLocal_PointDomain;
7113  nPointNode = nPoint;
7114 
7115  node = new CPoint*[nPoint];
7116 
7117  Local_to_Global_Point = new long[nPoint];
7118 
7119  /*--- Array initialization ---*/
7120 
7121  for (iPoint = 0; iPoint < nPoint; iPoint++) {
7122  Local_to_Global_Point[iPoint] = -1;
7123  }
7124 
7125  /*--- Set our counters correctly based on the number of owned and ghost
7126  nodes that we counted during the partitioning. ---*/
7127 
7128  jPoint = 0;
7129  iOwned = 0;
7130  iPeriodic = nLocal_PointDomain;
7131  iGhost = nLocal_PointDomain + nLocal_PointPeriodic;
7132 
7133  /*--- Loop over all of the points that we have recv'd and store the
7134  coordinates, global index, and colors ---*/
7135 
7136  for (iPoint = 0; iPoint < nPoint; iPoint++) {
7137 
7138  /*--- Set the starting point to the correct counter for this point. ---*/
7139 
7140  if (Local_Colors[iPoint] == (unsigned long)rank) {
7141  if (Local_Points[iPoint] < geometry->GetGlobal_nPointDomain())
7142  jPoint = iOwned;
7143  else jPoint = iPeriodic;
7144  } else {
7145  jPoint = iGhost;
7146  }
7147 
7148  /*--- Get the global index ---*/
7149 
7150  Local_to_Global_Point[jPoint] = Local_Points[iPoint];
7151 
7152  /*--- Allocating the Point object ---*/
7153 
7154  if ( nDim == 2 )
7155  node[jPoint] = new CPoint(Local_Coords[iPoint*nDim+0],
7156  Local_Coords[iPoint*nDim+1],
7157  Local_to_Global_Point[jPoint], config);
7158  if ( nDim == 3 )
7159  node[jPoint] = new CPoint(Local_Coords[iPoint*nDim+0],
7160  Local_Coords[iPoint*nDim+1],
7161  Local_Coords[iPoint*nDim+2],
7162  Local_to_Global_Point[jPoint], config);
7163 
7164  /*--- Set the color ---*/
7165 
7166  node[jPoint]->SetColor(Local_Colors[iPoint]);
7167 
7168  /*--- Increment the correct counter before moving to the next point. ---*/
7169 
7170  if (Local_Colors[iPoint] == (unsigned long)rank) {
7171  if (Local_Points[iPoint] < geometry->GetGlobal_nPointDomain())
7172  iOwned++;
7173  else iPeriodic++;
7174  } else {
7175  iGhost++;
7176  }
7177  }
7178 
7179  /*--- Create the global to local mapping, which will be useful for loading
7180  the elements and boundaries in subsequent steps. ---*/
7181 
7182  for (iPoint = 0; iPoint < nPoint; iPoint++)
7183  Global_to_Local_Point[Local_to_Global_Point[iPoint]] = iPoint;
7184 
7185  /*--- Set the value of Global_nPoint and Global_nPointDomain ---*/
7186 
7187  unsigned long Local_nPoint = nPoint;
7188  unsigned long Local_nPointDomain = nPointDomain;
7189 
7190 #ifdef HAVE_MPI
7191  SU2_MPI::Allreduce(&Local_nPoint, &Global_nPoint, 1,
7193  SU2_MPI::Allreduce(&Local_nPointDomain, &Global_nPointDomain, 1,
7195 #else
7196  Global_nPoint = Local_nPoint;
7197  Global_nPointDomain = Local_nPointDomain;
7198 #endif
7199 
7200  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
7201  cout << Global_nPoint << " vertices including ghost points. " << endl;
7202 
7203 }
7204 
7206 
7207  unsigned short NODES_PER_ELEMENT;
7208 
7209  unsigned long iElem, jElem, kElem, iNode, Local_Elem, iGlobal_Index;
7210  unsigned long Local_Nodes[N_POINTS_HEXAHEDRON];
7211 
7212  unsigned long iElemTria = 0;
7213  unsigned long iElemQuad = 0;
7214  unsigned long iElemTetr = 0;
7215  unsigned long iElemHexa = 0;
7216  unsigned long iElemPris = 0;
7217  unsigned long iElemPyra = 0;
7218 
7219  unsigned long nTria, nQuad, nTetr, nHexa, nPris, nPyra;
7220 
7221  map<unsigned long, unsigned long> Tria_List;
7222  map<unsigned long, unsigned long> Quad_List;
7223  map<unsigned long, unsigned long> Tetr_List;
7224  map<unsigned long, unsigned long> Hexa_List;
7225  map<unsigned long, unsigned long> Pris_List;
7226  map<unsigned long, unsigned long> Pyra_List;
7227  map<unsigned long, unsigned long>::iterator it;
7228 
7229  /*--- It is possible that we have repeated elements during the previous
7230  communications, as we mostly focus on the grid points and their colors.
7231  First, loop through our local elements and build a mapping by simply
7232  overwriting the duplicate entries. ---*/
7233 
7234  jElem = 0;
7235  for (iElem=0; iElem < nLocal_Tria; iElem++) {
7236  Tria_List[ID_Tria[iElem]] = iElem;
7237  }
7238  nTria = Tria_List.size();
7239 
7240  jElem = 0;
7241  for (iElem=0; iElem < nLocal_Quad; iElem++) {
7242  Quad_List[ID_Quad[iElem]] = iElem;
7243  }
7244  nQuad = Quad_List.size();
7245 
7246  jElem = 0;
7247  for (iElem=0; iElem < nLocal_Tetr; iElem++) {
7248  Tetr_List[ID_Tetr[iElem]] = iElem;
7249  }
7250  nTetr = Tetr_List.size();
7251 
7252  jElem = 0;
7253  for (iElem=0; iElem < nLocal_Hexa; iElem++) {
7254  Hexa_List[ID_Hexa[iElem]] = iElem;
7255  }
7256  nHexa = Hexa_List.size();
7257 
7258  jElem = 0;
7259  for (iElem=0; iElem < nLocal_Pris; iElem++) {
7260  Pris_List[ID_Pris[iElem]] = iElem;
7261  }
7262  nPris = Pris_List.size();
7263 
7264  jElem = 0;
7265  for (iElem=0; iElem < nLocal_Pyra; iElem++) {
7266  Pyra_List[ID_Pyra[iElem]] = iElem;
7267  }
7268  nPyra = Pyra_List.size();
7269 
7270  /*--- Reduce the final count of non-repeated elements on this rank. ---*/
7271 
7272  Local_Elem = nTria + nQuad + nTetr + nHexa + nPris + nPyra;
7273 
7274  /*--- Create the basic structures for holding the grid elements. ---*/
7275 
7276  jElem = 0;
7277  nElem = Local_Elem;
7278  elem = new CPrimalGrid*[nElem];
7279 
7280  /*--- Store the elements of each type in the proper containers. ---*/
7281 
7282  for (it = Tria_List.begin(); it != Tria_List.end(); it++) {
7283 
7284  kElem = it->first;
7285  iElem = it->second;
7286 
7287  /*--- Transform the stored connectivity for this element from global
7288  to local values on this rank. ---*/
7289 
7290  NODES_PER_ELEMENT = N_POINTS_TRIANGLE;
7291  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7292  iGlobal_Index = Conn_Tria[iElem*NODES_PER_ELEMENT+iNode];
7293  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7294  }
7295 
7296  /*--- Create the element object. ---*/
7297 
7298  elem[jElem] = new CTriangle(Local_Nodes[0],
7299  Local_Nodes[1],
7300  Local_Nodes[2], 2);
7301 
7302  elem[jElem]->SetGlobalIndex(kElem);
7303 
7304  /*--- Increment our local counters. ---*/
7305 
7306  jElem++; iElemTria++;
7307 
7308  }
7309 
7310  /*--- Free memory as we go. ---*/
7311 
7312  Tria_List.clear();
7313 
7314  for (it = Quad_List.begin(); it != Quad_List.end(); it++) {
7315 
7316  kElem = it->first;
7317  iElem = it->second;
7318 
7319  /*--- Transform the stored connectivity for this element from global
7320  to local values on this rank. ---*/
7321 
7322  NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL;
7323  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7324  iGlobal_Index = Conn_Quad[iElem*NODES_PER_ELEMENT+iNode];
7325  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7326  }
7327 
7328  /*--- Create the element object. ---*/
7329 
7330  elem[jElem] = new CQuadrilateral(Local_Nodes[0],
7331  Local_Nodes[1],
7332  Local_Nodes[2],
7333  Local_Nodes[3], 2);
7334 
7335  elem[jElem]->SetGlobalIndex(kElem);
7336 
7337  /*--- Increment our local counters. ---*/
7338 
7339  jElem++; iElemQuad++;
7340 
7341  }
7342 
7343  /*--- Free memory as we go. ---*/
7344 
7345  Quad_List.clear();
7346 
7347  for (it = Tetr_List.begin(); it != Tetr_List.end(); it++) {
7348 
7349  kElem = it->first;
7350  iElem = it->second;
7351 
7352  /*--- Transform the stored connectivity for this element from global
7353  to local values on this rank. ---*/
7354 
7355  NODES_PER_ELEMENT = N_POINTS_TETRAHEDRON;
7356  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7357  iGlobal_Index = Conn_Tetr[iElem*NODES_PER_ELEMENT+iNode];
7358  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7359  }
7360 
7361  /*--- Create the element object. ---*/
7362 
7363  elem[jElem] = new CTetrahedron(Local_Nodes[0],
7364  Local_Nodes[1],
7365  Local_Nodes[2],
7366  Local_Nodes[3]);
7367 
7368  elem[jElem]->SetGlobalIndex(kElem);
7369 
7370  /*--- Increment our local counters. ---*/
7371 
7372  jElem++; iElemTetr++;
7373 
7374  }
7375 
7376  /*--- Free memory as we go. ---*/
7377 
7378  Tetr_List.clear();
7379 
7380  for (it = Hexa_List.begin(); it != Hexa_List.end(); it++) {
7381 
7382  kElem = it->first;
7383  iElem = it->second;
7384 
7385  /*--- Transform the stored connectivity for this element from global
7386  to local values on this rank. ---*/
7387 
7388  NODES_PER_ELEMENT = N_POINTS_HEXAHEDRON;
7389  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7390  iGlobal_Index = Conn_Hexa[iElem*NODES_PER_ELEMENT+iNode];
7391  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7392  }
7393 
7394  /*--- Create the element object. ---*/
7395 
7396  elem[jElem] = new CHexahedron(Local_Nodes[0],
7397  Local_Nodes[1],
7398  Local_Nodes[2],
7399  Local_Nodes[3],
7400  Local_Nodes[4],
7401  Local_Nodes[5],
7402  Local_Nodes[6],
7403  Local_Nodes[7]);
7404 
7405  elem[jElem]->SetGlobalIndex(kElem);
7406 
7407  /*--- Increment our local counters. ---*/
7408 
7409  jElem++; iElemHexa++;
7410 
7411  }
7412 
7413  /*--- Free memory as we go. ---*/
7414 
7415  Hexa_List.clear();
7416 
7417  for (it = Pris_List.begin(); it != Pris_List.end(); it++) {
7418 
7419  kElem = it->first;
7420  iElem = it->second;
7421 
7422  /*--- Transform the stored connectivity for this element from global
7423  to local values on this rank. ---*/
7424 
7425  NODES_PER_ELEMENT = N_POINTS_PRISM;
7426  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7427  iGlobal_Index = Conn_Pris[iElem*NODES_PER_ELEMENT+iNode];
7428  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7429  }
7430 
7431  /*--- Create the element object. ---*/
7432 
7433  elem[jElem] = new CPrism(Local_Nodes[0],
7434  Local_Nodes[1],
7435  Local_Nodes[2],
7436  Local_Nodes[3],
7437  Local_Nodes[4],
7438  Local_Nodes[5]);
7439 
7440  elem[jElem]->SetGlobalIndex(kElem);
7441 
7442  /*--- Increment our local counters. ---*/
7443 
7444  jElem++; iElemPris++;
7445 
7446  }
7447 
7448  /*--- Free memory as we go. ---*/
7449 
7450  Pris_List.clear();
7451 
7452  for (it = Pyra_List.begin(); it != Pyra_List.end(); it++) {
7453 
7454  kElem = it->first;
7455  iElem = it->second;
7456 
7457  /*--- Transform the stored connectivity for this element from global
7458  to local values on this rank. ---*/
7459 
7460  NODES_PER_ELEMENT = N_POINTS_PYRAMID;
7461  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7462  iGlobal_Index = Conn_Pyra[iElem*NODES_PER_ELEMENT+iNode];
7463  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7464  }
7465 
7466  /*--- Create the element object. ---*/
7467 
7468  elem[jElem] = new CPyramid(Local_Nodes[0],
7469  Local_Nodes[1],
7470  Local_Nodes[2],
7471  Local_Nodes[3],
7472  Local_Nodes[4]);
7473 
7474  elem[jElem]->SetGlobalIndex(kElem);
7475 
7476  /*--- Increment our local counters. ---*/
7477 
7478  jElem++; iElemPyra++;
7479 
7480  }
7481 
7482  /*--- Free memory as we go. ---*/
7483 
7484  Pyra_List.clear();
7485 
7486  /*--- Communicate the number of each element type to all processors. These
7487  values are important for merging and writing output later. ---*/
7488 
7489 #ifdef HAVE_MPI
7490  SU2_MPI::Allreduce(&Local_Elem, &Global_nElem, 1,
7492 #else
7493  Global_nElem = nElem;
7494 #endif
7495 
7496  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
7497  cout << Global_nElem << " interior elements including halo cells. " << endl;
7498 
7499  /*--- Set the value of Global_nElemDomain (stored in the geometry
7500  container that is passed in). ---*/
7501 
7503 
7504  /*--- Store total number of each element type after incrementing the
7505  counters in the recv loop above (to make sure there aren't repeats). ---*/
7506 
7507  nelem_triangle = iElemTria;
7508  nelem_quad = iElemQuad;
7509  nelem_tetra = iElemTetr;
7510  nelem_hexa = iElemHexa;
7511  nelem_prism = iElemPris;
7512  nelem_pyramid = iElemPyra;
7513 
7514 #ifdef HAVE_MPI
7515  unsigned long Local_nElemTri = nelem_triangle;
7516  unsigned long Local_nElemQuad = nelem_quad;
7517  unsigned long Local_nElemTet = nelem_tetra;
7518  unsigned long Local_nElemHex = nelem_hexa;
7519  unsigned long Local_nElemPrism = nelem_prism;
7520  unsigned long Local_nElemPyramid = nelem_pyramid;
7521 
7522  SU2_MPI::Allreduce(&Local_nElemTri, &Global_nelem_triangle, 1,
7524  SU2_MPI::Allreduce(&Local_nElemQuad, &Global_nelem_quad, 1,
7526  SU2_MPI::Allreduce(&Local_nElemTet, &Global_nelem_tetra, 1,
7528  SU2_MPI::Allreduce(&Local_nElemHex, &Global_nelem_hexa, 1,
7530  SU2_MPI::Allreduce(&Local_nElemPrism, &Global_nelem_prism, 1,
7532  SU2_MPI::Allreduce(&Local_nElemPyramid, &Global_nelem_pyramid, 1,
7534 #else
7541 #endif
7542 
7543  /*--- Print information about the elements to the console ---*/
7544 
7545  if (rank == MASTER_NODE) {
7546  if (Global_nelem_triangle > 0)
7547  cout << Global_nelem_triangle << " triangles." << endl;
7548  if (Global_nelem_quad > 0)
7549  cout << Global_nelem_quad << " quadrilaterals." << endl;
7550  if (Global_nelem_tetra > 0)
7551  cout << Global_nelem_tetra << " tetrahedra." << endl;
7552  if (Global_nelem_hexa > 0)
7553  cout << Global_nelem_hexa << " hexahedra." << endl;
7554  if (Global_nelem_prism > 0)
7555  cout << Global_nelem_prism << " prisms." << endl;
7556  if (Global_nelem_pyramid > 0)
7557  cout << Global_nelem_pyramid << " pyramids." << endl;
7558  }
7559 
7560 }
7561 
7563 
7564  unsigned short NODES_PER_ELEMENT;
7565  unsigned short iNode, nMarker_Max = config->GetnMarker_Max();
7566 
7567  unsigned long iElem, iMarker, Global_Marker, iGlobal_Index;
7568 
7569  unsigned long iElem_Line = 0;
7570  unsigned long iElem_Tria = 0;
7571  unsigned long iElem_Quad = 0;
7572 
7573  unsigned long Local_Nodes[N_POINTS_HEXAHEDRON];
7574 
7575  vector<vector<unsigned long> > Line_List;
7576  vector<vector<unsigned long> > BoundTria_List;
7577  vector<vector<unsigned long> > BoundQuad_List;
7578 
7579  vector<unsigned long> Marker_Local;
7580  vector<unsigned long>::iterator it;
7581 
7582  /*--- Compute how many markers we have local to this rank by looping
7583  through the global marker numbers of each local surface element and
7584  counting the unique set. ---*/
7585 
7586  for (iElem = 0; iElem < nLocal_Line; iElem++) {
7587  if (find(Marker_Local.begin(), Marker_Local.end(),
7588  ID_Line[iElem]) == Marker_Local.end()) {
7589  Marker_Local.push_back(ID_Line[iElem]);
7590  }
7591  }
7592 
7593  for (iElem = 0; iElem < nLocal_BoundTria; iElem++) {
7594  if (find(Marker_Local.begin(), Marker_Local.end(),
7595  ID_BoundTria[iElem]) == Marker_Local.end()) {
7596  Marker_Local.push_back(ID_BoundTria[iElem]);
7597  }
7598  }
7599 
7600  for (iElem = 0; iElem < nLocal_BoundQuad; iElem++) {
7601  if (find(Marker_Local.begin(), Marker_Local.end(),
7602  ID_BoundQuad[iElem]) == Marker_Local.end()) {
7603  Marker_Local.push_back(ID_BoundQuad[iElem]);
7604  }
7605  }
7606 
7607  /*--- Create a mapping from global to local marker ID (and vice-versa). ---*/
7608 
7609  map<unsigned long, unsigned long> Marker_Global_to_Local;
7610  map<unsigned long, unsigned long> Marker_Local_to_Global;
7611 
7612  for (iMarker = 0; iMarker < Marker_Local.size(); iMarker++) {
7613  Marker_Global_to_Local[Marker_Local[iMarker]] = iMarker;
7614  Marker_Local_to_Global[iMarker] = Marker_Local[iMarker];
7615  }
7616 
7617  /*--- Set up our element counters on each marker so that we can avoid
7618  duplicating any elements from the previous communications. ---*/
7619 
7620  Line_List.resize(Marker_Local.size());
7621  BoundTria_List.resize(Marker_Local.size());
7622  BoundQuad_List.resize(Marker_Local.size());
7623 
7624  /*--- Count the number of elements on each marker and store in a
7625  vector by marker. ---*/
7626 
7627  vector<unsigned long> nElemBound_Local;
7628  nElemBound_Local.resize(Marker_Local.size());
7629  for (iMarker = 0; iMarker < Marker_Local.size(); iMarker++)
7630  nElemBound_Local[iMarker] = 0;
7631 
7632  for (iElem = 0; iElem < nLocal_Line; iElem++) {
7633  iMarker = Marker_Global_to_Local[ID_Line[iElem]];
7634  if (find(Line_List[iMarker].begin(), Line_List[iMarker].end(),
7635  Elem_ID_Line[iElem]) == Line_List[iMarker].end()) {
7636  nElemBound_Local[iMarker]++;
7637  Line_List[iMarker].push_back(Elem_ID_Line[iElem]);
7638  }
7639  }
7640 
7641  for (iElem = 0; iElem < nLocal_BoundTria; iElem++) {
7642  iMarker = Marker_Global_to_Local[ID_BoundTria[iElem]];
7643  if (find(BoundTria_List[iMarker].begin(), BoundTria_List[iMarker].end(),
7644  Elem_ID_BoundTria[iElem]) == BoundTria_List[iMarker].end()) {
7645  nElemBound_Local[iMarker]++;
7646  BoundTria_List[iMarker].push_back(Elem_ID_BoundTria[iElem]);
7647  }
7648  }
7649 
7650  for (iElem = 0; iElem < nLocal_BoundQuad; iElem++) {
7651  iMarker = Marker_Global_to_Local[ID_BoundQuad[iElem]];
7652  if (find(BoundQuad_List[iMarker].begin(), BoundQuad_List[iMarker].end(),
7653  Elem_ID_BoundQuad[iElem]) == BoundQuad_List[iMarker].end()) {
7654  nElemBound_Local[iMarker]++;
7655  BoundQuad_List[iMarker].push_back(Elem_ID_BoundQuad[iElem]);
7656  }
7657  }
7658 
7659  /*--- Create the domain structures for the boundaries. Initially, stick
7660  with nMarkerMax here, but come back and compute size we need. Same for
7661  OVERHEAD - this can precomputed. ---*/
7662 
7663  nMarker = Marker_Local.size();
7664  nElem_Bound = new unsigned long[nMarker_Max];
7665  Tag_to_Marker = new string[nMarker_Max];
7666  Marker_All_SendRecv = new short[nMarker_Max];
7667 
7668  /*--- Allocate space for the elements on each marker ---*/
7669 
7670  for (iMarker = 0; iMarker < nMarker; iMarker++)
7671  nElem_Bound[iMarker] = nElemBound_Local[iMarker];
7672 
7673  bound = new CPrimalGrid**[nMarker+(OVERHEAD*size)];
7674  for (iMarker = 0; iMarker < nMarker+(OVERHEAD*size); iMarker++)
7675  bound[iMarker] = NULL;
7676 
7677  for (iMarker = 0; iMarker < nMarker; iMarker++)
7678  bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]];
7679 
7680  /*--- Initialize boundary element counters ---*/
7681 
7682  iElem_Line = 0;
7683  iElem_Tria = 0;
7684  iElem_Quad = 0;
7685 
7686  Line_List.clear(); Line_List.resize(Marker_Local.size());
7687  BoundTria_List.clear(); BoundTria_List.resize(Marker_Local.size());
7688  BoundQuad_List.clear(); BoundQuad_List.resize(Marker_Local.size());
7689 
7690  /*--- Reset our element counter on a marker-basis. ---*/
7691 
7692  for (iMarker = 0; iMarker < nMarker; iMarker++)
7693  nElemBound_Local[iMarker] = 0;
7694 
7695  /*--- Store the boundary element connectivity. Note here that we have
7696  communicated the global index values for the elements, so we need to
7697  convert this to the local index when instantiating the element. ---*/
7698 
7699  for (iElem = 0; iElem < nLocal_Line; iElem++) {
7700 
7701  iMarker = Marker_Global_to_Local[ID_Line[iElem]];
7702 
7703  /*--- Avoid duplicates on this marker. ---*/
7704 
7705  if (find(Line_List[iMarker].begin(), Line_List[iMarker].end(),
7706  Elem_ID_Line[iElem]) == Line_List[iMarker].end()) {
7707 
7708  /*--- Transform the stored connectivity for this element from global
7709  to local values on this rank. ---*/
7710 
7711  NODES_PER_ELEMENT = N_POINTS_LINE;
7712  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7713  iGlobal_Index = Conn_Line[iElem*NODES_PER_ELEMENT+iNode];
7714  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7715  }
7716 
7717  /*--- Create the geometry object for this element. ---*/
7718 
7719  bound[iMarker][nElemBound_Local[iMarker]] = new CLine(Local_Nodes[0],
7720  Local_Nodes[1], 2);
7721 
7722  /*--- Increment our counters for this marker and element type. ---*/
7723 
7724  nElemBound_Local[iMarker]++; iElem_Line++;
7725 
7726  Line_List[iMarker].push_back(Elem_ID_Line[iElem]);
7727 
7728  }
7729  }
7730 
7731  for (iElem = 0; iElem < nLocal_BoundTria; iElem++) {
7732 
7733  iMarker = Marker_Global_to_Local[ID_BoundTria[iElem]];
7734 
7735  /*--- Avoid duplicates on this marker. ---*/
7736 
7737  if (find(BoundTria_List[iMarker].begin(), BoundTria_List[iMarker].end(),
7738  Elem_ID_BoundTria[iElem]) == BoundTria_List[iMarker].end()) {
7739 
7740  /*--- Transform the stored connectivity for this element from global
7741  to local values on this rank. ---*/
7742 
7743  NODES_PER_ELEMENT = N_POINTS_TRIANGLE;
7744  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7745  iGlobal_Index = Conn_BoundTria[iElem*NODES_PER_ELEMENT+iNode];
7746  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7747  }
7748 
7749  /*--- Create the geometry object for this element. ---*/
7750 
7751  bound[iMarker][nElemBound_Local[iMarker]] = new CTriangle(Local_Nodes[0],
7752  Local_Nodes[1],
7753  Local_Nodes[2], 3);
7754 
7755  /*--- Increment our counters for this marker and element type. ---*/
7756 
7757  nElemBound_Local[iMarker]++; iElem_Tria++;
7758 
7759  BoundTria_List[iMarker].push_back(Elem_ID_BoundTria[iElem]);
7760 
7761  }
7762  }
7763 
7764  for (iElem = 0; iElem < nLocal_BoundQuad; iElem++) {
7765 
7766  iMarker = Marker_Global_to_Local[ID_BoundQuad[iElem]];
7767 
7768  /*--- Avoid duplicates on this marker. ---*/
7769 
7770  if (find(BoundQuad_List[iMarker].begin(), BoundQuad_List[iMarker].end(),
7771  Elem_ID_BoundQuad[iElem]) == BoundQuad_List[iMarker].end()) {
7772 
7773  /*--- Transform the stored connectivity for this element from global
7774  to local values on this rank. ---*/
7775 
7776  NODES_PER_ELEMENT = N_POINTS_QUADRILATERAL;
7777  for (iNode = 0; iNode < NODES_PER_ELEMENT; iNode++) {
7778  iGlobal_Index = Conn_BoundQuad[iElem*NODES_PER_ELEMENT+iNode];
7779  Local_Nodes[iNode] = Global_to_Local_Point[iGlobal_Index];
7780  }
7781 
7782  /*--- Create the geometry object for this element. ---*/
7783 
7784  bound[iMarker][nElemBound_Local[iMarker]] = new CQuadrilateral(Local_Nodes[0],
7785  Local_Nodes[1],
7786  Local_Nodes[2],
7787  Local_Nodes[3], 3);
7788 
7789  /*--- Increment our counters for this marker and element type. ---*/
7790 
7791  nElemBound_Local[iMarker]++; iElem_Quad++;
7792 
7793  BoundQuad_List[iMarker].push_back(Elem_ID_BoundQuad[iElem]);
7794 
7795  }
7796  }
7797 
7798  /*--- Store total number of each boundary element type ---*/
7799 
7800  nelem_edge_bound = iElem_Line;
7801  nelem_triangle_bound = iElem_Tria;
7802  nelem_quad_bound = iElem_Quad;
7803 
7804  /*--- Set some auxiliary information on a per-marker basis. ---*/
7805 
7806  for (iMarker = 0; iMarker < nMarker; iMarker++) {
7807 
7808  Global_Marker = Marker_Local_to_Global[iMarker];
7809 
7810  /*--- Now each domain has the right information ---*/
7811 
7812  string Grid_Marker = config->GetMarker_All_TagBound(Marker_Local_to_Global[iMarker]);
7813  short SendRecv = config->GetMarker_All_SendRecv(Marker_Local_to_Global[iMarker]);
7814 
7815  Tag_to_Marker[iMarker] = Marker_Tags[Global_Marker];
7816  Marker_All_SendRecv[iMarker] = SendRecv;
7817 
7818  /*--- Set the marker tags correctly to match the values in config. ---*/
7819 
7820  config->SetMarker_All_TagBound(iMarker, Tag_to_Marker[iMarker]);
7821  config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]);
7822 
7823  }
7824 
7825  /*--- Initialize pointers for turbomachinery computations ---*/
7826 
7827  nSpanWiseSections = new unsigned short[2];
7828  SpanWiseValue = new su2double*[2];
7829  for (unsigned short iMarker = 0; iMarker < 2; iMarker++){
7830  nSpanWiseSections[iMarker] = 0;
7831  SpanWiseValue[iMarker] = NULL;
7832  }
7833 
7834  nVertexSpan = new long* [nMarker];
7835  nTotVertexSpan = new unsigned long* [nMarker];
7836  turbovertex = new CTurboVertex***[nMarker];
7838  AverageNormal = new su2double**[nMarker];
7839  AverageGridVel = new su2double**[nMarker];
7841  SpanArea = new su2double*[nMarker];
7842  TurboRadius = new su2double*[nMarker];
7846 
7847  for (unsigned short iMarker = 0; iMarker < nMarker; iMarker++){
7848  nVertexSpan[iMarker] = NULL;
7849  nTotVertexSpan[iMarker] = NULL;
7850  turbovertex[iMarker] = NULL;
7851  AverageTurboNormal[iMarker] = NULL;
7852  AverageNormal[iMarker] = NULL;
7853  AverageGridVel[iMarker] = NULL;
7854  AverageTangGridVel[iMarker] = NULL;
7855  SpanArea[iMarker] = NULL;
7856  TurboRadius[iMarker] = NULL;
7857  MaxAngularCoord[iMarker] = NULL;
7858  MinAngularCoord[iMarker] = NULL;
7859  MinRelAngularCoord[iMarker] = NULL;
7860  }
7861 
7862  /*--- Initialize pointers for turbomachinery performance computation ---*/
7863 
7871 
7872  for (unsigned short iMarker = 0; iMarker < config->GetnMarker_TurboPerformance(); iMarker++){
7873  TangGridVelIn[iMarker] = NULL;
7874  SpanAreaIn[iMarker] = NULL;
7875  TurboRadiusIn[iMarker] = NULL;
7876  TangGridVelOut[iMarker] = NULL;
7877  SpanAreaOut[iMarker] = NULL;
7878  TurboRadiusOut[iMarker] = NULL;
7879  }
7880 
7881 }
7882 
7884  int *nElemSend,
7885  SU2_MPI::Request *sendReq,
7886  void *bufRecv,
7887  int *nElemRecv,
7888  SU2_MPI::Request *recvReq,
7889  unsigned short countPerElem,
7890  unsigned short commType) {
7891 
7892  /*--- Local variables ---*/
7893 
7894  int iMessage, iProc, offset, nElem, count, source, dest, tag;
7895 
7896  /*--- Launch the non-blocking recv's first. ---*/
7897 
7898  iMessage = 0;
7899  for (iProc = 0; iProc < size; iProc++) {
7900 
7901  /*--- Post recv's only if another proc is sending us data. We do
7902  not communicate with ourselves or post recv's for zero length
7903  messages to keep overhead down. ---*/
7904 
7905  if ((nElemRecv[iProc+1] > nElemRecv[iProc]) && (iProc != rank)) {
7906 
7907  /*--- Compute our location in the recv buffer. ---*/
7908 
7909  offset = countPerElem*nElemRecv[iProc];
7910 
7911  /*--- Take advantage of cumulative storage format to get the number
7912  of elems that we need to recv. ---*/
7913 
7914  nElem = nElemRecv[iProc+1] - nElemRecv[iProc];
7915 
7916  /*--- Total count can include multiple pieces of data per element. ---*/
7917 
7918  count = countPerElem*nElem;
7919 
7920  /*--- Post non-blocking recv for this proc. ---*/
7921 
7922  source = iProc; tag = iProc + 1;
7923 
7924  switch (commType) {
7925  case COMM_TYPE_DOUBLE:
7926  SU2_MPI::Irecv(&(static_cast<su2double*>(bufRecv)[offset]),
7927  count, MPI_DOUBLE, source, tag, MPI_COMM_WORLD,
7928  &(recvReq[iMessage]));
7929  break;
7931  SU2_MPI::Irecv(&(static_cast<unsigned long*>(bufRecv)[offset]),
7932  count, MPI_UNSIGNED_LONG, source, tag, MPI_COMM_WORLD,
7933  &(recvReq[iMessage]));
7934  break;
7935  case COMM_TYPE_LONG:
7936  SU2_MPI::Irecv(&(static_cast<long*>(bufRecv)[offset]),
7937  count, MPI_LONG, source, tag, MPI_COMM_WORLD,
7938  &(recvReq[iMessage]));
7939  break;
7941  SU2_MPI::Irecv(&(static_cast<unsigned short*>(bufRecv)[offset]),
7942  count, MPI_UNSIGNED_SHORT, source, tag, MPI_COMM_WORLD,
7943  &(recvReq[iMessage]));
7944  break;
7945  case COMM_TYPE_CHAR:
7946  SU2_MPI::Irecv(&(static_cast<char*>(bufRecv)[offset]),
7947  count, MPI_CHAR, source, tag, MPI_COMM_WORLD,
7948  &(recvReq[iMessage]));
7949  break;
7950  case COMM_TYPE_SHORT:
7951  SU2_MPI::Irecv(&(static_cast<short*>(bufRecv)[offset]),
7952  count, MPI_SHORT, source, tag, MPI_COMM_WORLD,
7953  &(recvReq[iMessage]));
7954  break;
7955  case COMM_TYPE_INT:
7956  SU2_MPI::Irecv(&(static_cast<int*>(bufRecv)[offset]),
7957  count, MPI_INT, source, tag, MPI_COMM_WORLD,
7958  &(recvReq[iMessage]));
7959  break;
7960  default:
7961  break;
7962  }
7963 
7964  /*--- Increment message counter. ---*/
7965 
7966  iMessage++;
7967 
7968  }
7969  }
7970 
7971  /*--- Launch the non-blocking sends next. ---*/
7972 
7973  iMessage = 0;
7974  for (iProc = 0; iProc < size; iProc++) {
7975 
7976  /*--- Post sends only if we are sending another proc data. We do
7977  not communicate with ourselves or post sends for zero length
7978  messages to keep overhead down. ---*/
7979 
7980  if ((nElemSend[iProc+1] > nElemSend[iProc]) && (iProc != rank)) {
7981 
7982  /*--- Compute our location in the send buffer. ---*/
7983 
7984  offset = countPerElem*nElemSend[iProc];
7985 
7986  /*--- Take advantage of cumulative storage format to get the number
7987  of elems that we need to send. ---*/
7988 
7989  nElem = nElemSend[iProc+1] - nElemSend[iProc];
7990 
7991  /*--- Total count can include multiple pieces of data per element. ---*/
7992 
7993  count = countPerElem*nElem;
7994 
7995  /*--- Post non-blocking send for this proc. ---*/
7996 
7997  dest = iProc; tag = rank + 1;
7998 
7999  switch (commType) {
8000  case COMM_TYPE_DOUBLE:
8001  SU2_MPI::Isend(&(static_cast<su2double*>(bufSend)[offset]),
8002  count, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD,
8003  &(sendReq[iMessage]));
8004  break;
8006  SU2_MPI::Isend(&(static_cast<unsigned long*>(bufSend)[offset]),
8007  count, MPI_UNSIGNED_LONG, dest, tag, MPI_COMM_WORLD,
8008  &(sendReq[iMessage]));
8009  break;
8010  case COMM_TYPE_LONG:
8011  SU2_MPI::Isend(&(static_cast<long*>(bufSend)[offset]),
8012  count, MPI_LONG, dest, tag, MPI_COMM_WORLD,
8013  &(sendReq[iMessage]));
8014  break;
8016  SU2_MPI::Isend(&(static_cast<unsigned short*>(bufSend)[offset]),
8017  count, MPI_UNSIGNED_SHORT, dest, tag, MPI_COMM_WORLD,
8018  &(sendReq[iMessage]));
8019  break;
8020  case COMM_TYPE_CHAR:
8021  SU2_MPI::Isend(&(static_cast<char*>(bufSend)[offset]),
8022  count, MPI_CHAR, dest, tag, MPI_COMM_WORLD,
8023  &(sendReq[iMessage]));
8024  break;
8025  case COMM_TYPE_SHORT:
8026  SU2_MPI::Isend(&(static_cast<short*>(bufSend)[offset]),
8027  count, MPI_SHORT, dest, tag, MPI_COMM_WORLD,
8028  &(sendReq[iMessage]));
8029  break;
8030  case COMM_TYPE_INT:
8031  SU2_MPI::Isend(&(static_cast<int*>(bufSend)[offset]),
8032  count, MPI_INT, dest, tag, MPI_COMM_WORLD,
8033  &(sendReq[iMessage]));
8034  break;
8035  default:
8036  break;
8037  }
8038 
8039  /*--- Increment message counter. ---*/
8040 
8041  iMessage++;
8042 
8043  }
8044  }
8045 
8046 }
8047 
8049  SU2_MPI::Request *sendReq,
8050  int nRecvs,
8051  SU2_MPI::Request *recvReq) {
8052 
8053  /*--- Local variables ---*/
8054 
8055  int ind, iSend, iRecv;
8056  SU2_MPI::Status status;
8057 
8058  /*--- Wait for the non-blocking sends to complete. ---*/
8059 
8060  for (iSend = 0; iSend < nSends; iSend++)
8061  SU2_MPI::Waitany(nSends, sendReq, &ind, &status);
8062 
8063  /*--- Wait for the non-blocking recvs to complete. ---*/
8064 
8065  for (iRecv = 0; iRecv < nRecvs; iRecv++)
8066  SU2_MPI::Waitany(nRecvs, recvReq, &ind, &status);
8067 
8068 }
8069 
8071 
8072  unsigned short Counter_Send, Counter_Receive, iMarkerSend, iMarkerReceive;
8073  unsigned long iVertex, LocalNode;
8074  unsigned short nMarker_Max = config->GetnMarker_Max();
8075  unsigned long iPoint, jPoint, iElem;
8076  unsigned long *nVertexDomain = new unsigned long[nMarker_Max];
8077  unsigned short nDomain, iNode, iDomain, jDomain, jNode;
8078  vector<unsigned long>::iterator it;
8079 
8080  vector<vector<unsigned long> > SendTransfLocal;
8081  vector<vector<unsigned long> > ReceivedTransfLocal;
8082  vector<vector<unsigned long> > SendDomainLocal;
8083  vector<vector<unsigned long> > ReceivedDomainLocal;
8085  map<unsigned long, unsigned long>::const_iterator MI;
8086 
8087  if (rank == MASTER_NODE && size > SINGLE_NODE)
8088  cout << "Establishing MPI communication patterns." << endl;
8089 
8090  nDomain = size;
8091 
8092  SendTransfLocal.resize(nDomain);
8093  ReceivedTransfLocal.resize(nDomain);
8094  SendDomainLocal.resize(nDomain);
8095  ReceivedDomainLocal.resize(nDomain);
8096 
8097  /*--- Loop over the all the points of the elements on this rank in order
8098  to find the points with different colors. Create the send/received lists
8099  from this information. ---*/
8100 
8101  for (iElem = 0; iElem < nElem; iElem++) {
8102  for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) {
8103 
8104  iPoint = elem[iElem]->GetNode(iNode);
8105  iDomain = node[iPoint]->GetColor();
8106 
8107  if (iDomain == rank) {
8108  for (jNode = 0; jNode < elem[iElem]->GetnNodes(); jNode++) {
8109 
8110  jPoint = elem[iElem]->GetNode(jNode);
8111  jDomain = node[jPoint]->GetColor();
8112 
8113  /*--- If one of the neighbors is a different color and connected
8114  by an edge, then we add them to the list. ---*/
8115 
8116  if (iDomain != jDomain) {
8117 
8118  /*--- We send from iDomain to jDomain the value of iPoint,
8119  we save the global value becuase we need to sort the lists. ---*/
8120 
8121  SendDomainLocal[jDomain].push_back(Local_to_Global_Point[iPoint]);
8122 
8123  /*--- We send from jDomain to iDomain the value of jPoint,
8124  we save the global value becuase we need to sort the lists. ---*/
8125 
8126  ReceivedDomainLocal[jDomain].push_back(Local_to_Global_Point[jPoint]);
8127 
8128  }
8129  }
8130  }
8131  }
8132  }
8133 
8134  /*--- Sort the points that must be sent and delete repeated points, note
8135  that the sorting should be done with the global index (not the local). ---*/
8136 
8137  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8138  sort(SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end());
8139  it = unique(SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end());
8140  SendDomainLocal[iDomain].resize(it - SendDomainLocal[iDomain].begin());
8141  }
8142 
8143  /*--- Sort the points that must be received and delete repeated points, note
8144  that the sorting should be done with the global point (not the local). ---*/
8145 
8146  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8147  sort(ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end());
8148  it = unique( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end());
8149  ReceivedDomainLocal[iDomain].resize(it - ReceivedDomainLocal[iDomain].begin());
8150  }
8151 
8152  /*--- Create Global to Local Point array, note that the array is smaller (Max_GlobalPoint) than the total
8153  number of points in the simulation ---*/
8154  Max_GlobalPoint = 0;
8155  for (iPoint = 0; iPoint < nPoint; iPoint++) {
8156  if (Local_to_Global_Point[iPoint] > (long)Max_GlobalPoint)
8157  Max_GlobalPoint = Local_to_Global_Point[iPoint];
8158  }
8159 
8160  /*--- Set the value of some of the points ---*/
8161  for (iPoint = 0; iPoint < nPoint; iPoint++)
8162  Global_to_Local_Point[Local_to_Global_Point[iPoint]] = iPoint;
8163 
8164  /*--- Add the new MPI send boundaries, reset the transformation,
8165  and save the local value. ---*/
8166 
8167  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8168  if (SendDomainLocal[iDomain].size() != 0) {
8169  nVertexDomain[nMarker] = SendDomainLocal[iDomain].size();
8170  for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) {
8171 
8172  MI = Global_to_Local_Point.find(SendDomainLocal[iDomain][iVertex]);
8173  if (MI != Global_to_Local_Point.end())
8174  iPoint = Global_to_Local_Point[SendDomainLocal[iDomain][iVertex]];
8175  else iPoint = -1;
8176 
8177  SendDomainLocal[iDomain][iVertex] = iPoint;
8178  SendTransfLocal[iDomain].push_back(0);
8179  }
8180  nElem_Bound[nMarker] = nVertexDomain[nMarker];
8182  nMarker++;
8183  }
8184  }
8185 
8186  /*--- Add the new MPI receive boundaries, reset the transformation, and save the local value ---*/
8187  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8188  if (ReceivedDomainLocal[iDomain].size() != 0) {
8189  nVertexDomain[nMarker] = ReceivedDomainLocal[iDomain].size();
8190  for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) {
8191 
8192  MI = Global_to_Local_Point.find(ReceivedDomainLocal[iDomain][iVertex]);
8193  if (MI != Global_to_Local_Point.end())
8194  iPoint = Global_to_Local_Point[ReceivedDomainLocal[iDomain][iVertex]];
8195  else iPoint = -1;
8196 
8197  ReceivedDomainLocal[iDomain][iVertex] = iPoint;
8198  ReceivedTransfLocal[iDomain].push_back(0);
8199  }
8200  nElem_Bound[nMarker] = nVertexDomain[nMarker];
8202  nMarker++;
8203  }
8204  }
8205 
8206  /*--- First compute the Send/Receive boundaries ---*/
8207  Counter_Send = 0; Counter_Receive = 0;
8208  for (iDomain = 0; iDomain < nDomain; iDomain++)
8209  if (SendDomainLocal[iDomain].size() != 0) Counter_Send++;
8210 
8211  for (iDomain = 0; iDomain < nDomain; iDomain++)
8212  if (ReceivedDomainLocal[iDomain].size() != 0) Counter_Receive++;
8213 
8214  iMarkerSend = nMarker - Counter_Send - Counter_Receive;
8215  iMarkerReceive = nMarker - Counter_Receive;
8216 
8217  /*--- First we do the send ---*/
8218  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8219  if (SendDomainLocal[iDomain].size() != 0) {
8220  for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerSend); iVertex++) {
8221  LocalNode = SendDomainLocal[iDomain][iVertex];
8222  bound[iMarkerSend][iVertex] = new CVertexMPI(LocalNode, nDim);
8223  bound[iMarkerSend][iVertex]->SetRotation_Type(SendTransfLocal[iDomain][iVertex]);
8224  }
8225  Marker_All_SendRecv[iMarkerSend] = iDomain+1;
8226  iMarkerSend++;
8227  }
8228  }
8229 
8230  /*--- Second we do the receive ---*/
8231  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8232  if (ReceivedDomainLocal[iDomain].size() != 0) {
8233  for (iVertex = 0; iVertex < GetnElem_Bound(iMarkerReceive); iVertex++) {
8234  LocalNode = ReceivedDomainLocal[iDomain][iVertex];
8235  bound[iMarkerReceive][iVertex] = new CVertexMPI(LocalNode, nDim);
8236  bound[iMarkerReceive][iVertex]->SetRotation_Type(ReceivedTransfLocal[iDomain][iVertex]);
8237  }
8238  Marker_All_SendRecv[iMarkerReceive] = -(iDomain+1);
8239  iMarkerReceive++;
8240  }
8241  }
8242 
8243  /*--- Free memory ---*/
8244 
8245  delete [] nVertexDomain;
8246 
8247 }
8248 
8250 
8251  unsigned long iElem_Bound, TotalElem, *nElem_Bound_Copy, iVertex_;
8252  string Grid_Marker;
8253  unsigned short iDomain, nDomain, iMarkersDomain, iLoop, *DomainCount, nMarker_Physical, Duplicate_SendReceive, *DomainSendCount, **DomainSendMarkers, *DomainReceiveCount, **DomainReceiveMarkers, nMarker_SendRecv, iMarker, iMarker_;
8254  CPrimalGrid*** bound_Copy;
8255  short *Marker_All_SendRecv_Copy;
8256  bool CheckStart;
8257 
8258  nDomain = size+1;
8259 
8260  /*--- Count the number of physical markers
8261  in the boundaries ---*/
8262 
8263  nMarker_Physical = 0;
8264  for (iMarker = 0; iMarker < nMarker; iMarker++) {
8265  if (bound[iMarker][0]->GetVTK_Type() != VERTEX) {
8266  nMarker_Physical++;
8267  }
8268  }
8269 
8270  /*--- Identify if there are markers that send/received with the same domain,
8271  they should be together---*/
8272 
8273  Duplicate_SendReceive = 0;
8274  for (iLoop = 0; iLoop < 2; iLoop++) {
8275 
8276  DomainCount = new unsigned short [nDomain];
8277 
8278  for (iDomain = 0; iDomain < nDomain; iDomain++)
8279  DomainCount[iDomain] = 0;
8280 
8281  if (iLoop == 0) {
8282  for (iDomain = 0; iDomain < nDomain; iDomain++)
8283  for (iMarker = 0; iMarker < nMarker; iMarker++)
8284  if (bound[iMarker][0]->GetVTK_Type() == VERTEX)
8285  if (Marker_All_SendRecv[iMarker] == iDomain) DomainCount[iDomain]++;
8286  }
8287  else {
8288  for (iDomain = 0; iDomain < nDomain; iDomain++)
8289  for (iMarker = 0; iMarker < nMarker; iMarker++)
8290  if (bound[iMarker][0]->GetVTK_Type() == VERTEX)
8291  if (Marker_All_SendRecv[iMarker] == -iDomain) DomainCount[iDomain]++;
8292  }
8293 
8294  for (iDomain = 0; iDomain < nDomain; iDomain++)
8295  if (DomainCount[iDomain] > 1) Duplicate_SendReceive++;
8296 
8297  delete [] DomainCount;
8298 
8299  }
8300 
8301  DomainSendCount = new unsigned short [nDomain];
8302  DomainSendMarkers = new unsigned short *[nDomain];
8303  DomainReceiveCount = new unsigned short [nDomain];
8304  DomainReceiveMarkers = new unsigned short *[nDomain];
8305 
8306  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8307  DomainSendCount[iDomain] = 0;
8308  DomainSendMarkers[iDomain] = new unsigned short [nMarker];
8309 
8310  DomainReceiveCount[iDomain] = 0;
8311  DomainReceiveMarkers[iDomain] = new unsigned short [nMarker];
8312  }
8313 
8314  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8315  for (iMarker = 0; iMarker < nMarker; iMarker++) {
8316  if (bound[iMarker][0]->GetVTK_Type() == VERTEX) {
8317  if (Marker_All_SendRecv[iMarker] == iDomain) {
8318  DomainSendMarkers[iDomain][DomainSendCount[iDomain]] = iMarker;
8319  DomainSendCount[iDomain]++;
8320  }
8321  if (Marker_All_SendRecv[iMarker] == -iDomain) {
8322  DomainReceiveMarkers[iDomain][DomainReceiveCount[iDomain]] = iMarker;
8323  DomainReceiveCount[iDomain]++;
8324  }
8325  }
8326  }
8327  }
8328 
8329  /*--- Create an structure to store the Send/Receive
8330  boundaries, because they require some reorganization ---*/
8331 
8332  nMarker_SendRecv = nMarker - nMarker_Physical - Duplicate_SendReceive;
8333  bound_Copy = new CPrimalGrid**[nMarker_Physical + nMarker_SendRecv];
8334  nElem_Bound_Copy = new unsigned long [nMarker_Physical + nMarker_SendRecv];
8335  Marker_All_SendRecv_Copy = new short [nMarker_Physical + nMarker_SendRecv];
8336  iMarker_ = nMarker_Physical;
8337  iVertex_ = 0;
8338  CheckStart = false;
8339 
8340  /*--- Copy and allocate the physical markers in the data structure ---*/
8341 
8342  for (iMarker = 0; iMarker < nMarker; iMarker++) {
8343  if (bound[iMarker][0]->GetVTK_Type() != VERTEX) {
8344 
8345  nElem_Bound_Copy[iMarker] = nElem_Bound[iMarker];
8346  bound_Copy[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]];
8347 
8348  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
8349  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == LINE)
8350  bound_Copy[iMarker][iElem_Bound] = new CLine(bound[iMarker][iElem_Bound]->GetNode(0),
8351  bound[iMarker][iElem_Bound]->GetNode(1), 2);
8352  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE)
8353 
8354  bound_Copy[iMarker][iElem_Bound] = new CTriangle(bound[iMarker][iElem_Bound]->GetNode(0),
8355  bound[iMarker][iElem_Bound]->GetNode(1),
8356  bound[iMarker][iElem_Bound]->GetNode(2), 3);
8357  if (bound[iMarker][iElem_Bound]->GetVTK_Type() == QUADRILATERAL)
8358  bound_Copy[iMarker][iElem_Bound] = new CQuadrilateral(bound[iMarker][iElem_Bound]->GetNode(0),
8359  bound[iMarker][iElem_Bound]->GetNode(1),
8360  bound[iMarker][iElem_Bound]->GetNode(2),
8361  bound[iMarker][iElem_Bound]->GetNode(3), 3);
8362  }
8363  }
8364  }
8365 
8366 
8367  for (iDomain = 0; iDomain < nDomain; iDomain++) {
8368 
8369  /*--- Compute the total number of elements (adding all the
8370  boundaries with the same Send/Receive ---*/
8371 
8372  if (DomainSendCount[iDomain] != 0) {
8373  TotalElem = 0;
8374  for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) {
8375  iMarker = DomainSendMarkers[iDomain][iMarkersDomain];
8376  TotalElem += nElem_Bound[iMarker];
8377  }
8378  if (CheckStart) iMarker_++;
8379  CheckStart = true;
8380  iVertex_ = 0;
8381  nElem_Bound_Copy[iMarker_] = TotalElem;
8382  bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem];
8383  }
8384 
8385  for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) {
8386  iMarker = DomainSendMarkers[iDomain][iMarkersDomain];
8387  Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker];
8388 
8389  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
8390  bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim);
8391  bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type());
8392  iVertex_++;
8393  }
8394 
8395  }
8396 
8397  /*--- Compute the total number of elements (adding all the
8398  boundaries with the same Send/Receive ---*/
8399 
8400  if (DomainReceiveCount[iDomain] != 0) {
8401  TotalElem = 0;
8402  for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) {
8403  iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain];
8404  TotalElem += nElem_Bound[iMarker];
8405  }
8406  if (CheckStart) iMarker_++;
8407  CheckStart = true;
8408  iVertex_ = 0;
8409  nElem_Bound_Copy[iMarker_] = TotalElem;
8410  bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem];
8411 
8412  }
8413 
8414  for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) {
8415  iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain];
8416  Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker];
8417 
8418  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
8419  bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim);
8420  bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type());
8421  iVertex_++;
8422  }
8423 
8424  }
8425 
8426  }
8427 
8428  delete [] DomainSendCount;
8429  for (iDomain = 0; iDomain < nDomain; iDomain++)
8430  delete [] DomainSendMarkers[iDomain];
8431  delete[] DomainSendMarkers;
8432 
8433  delete [] DomainReceiveCount;
8434  for (iDomain = 0; iDomain < nDomain; iDomain++)
8435  delete [] DomainReceiveMarkers[iDomain];
8436  delete[] DomainReceiveMarkers;
8437 
8438  /*--- Deallocate the bound variables ---*/
8439 
8440  for (iMarker = 0; iMarker < nMarker; iMarker++) {
8441  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++)
8442  if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound];
8443  if (bound[iMarker] != NULL) delete [] bound[iMarker];
8444  }
8445  if (bound != NULL) delete [] bound;
8446 
8447  /*--- Allocate the new bound variables, and set the number of markers ---*/
8448 
8449  bound = bound_Copy;
8450  nMarker = nMarker_Physical + nMarker_SendRecv;
8451 
8452  config->SetnMarker_All(nMarker);
8453 
8454  for (iMarker = 0; iMarker < nMarker; iMarker++) {
8455  nElem_Bound[iMarker] = nElem_Bound_Copy[iMarker];
8456  }
8457  for (iMarker = nMarker_Physical; iMarker < nMarker; iMarker++) {
8458  Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker];
8459  config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]);
8460  config->SetMarker_All_TagBound(iMarker, "SEND_RECEIVE");
8461  }
8462 
8463  /*--- Update config information storing the boundary information in the right place ---*/
8464 
8465  for (iMarker = 0 ; iMarker < nMarker; iMarker++) {
8466 
8467  string Marker_Tag = config->GetMarker_All_TagBound(iMarker);
8468 
8469  if (Marker_Tag != "SEND_RECEIVE") {
8470 
8471  /*--- Update config information storing the boundary information in the right place ---*/
8472 
8473  Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag;
8474  config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag));
8475  config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag));
8476  config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag));
8477  config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag));
8478  config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag));
8479  config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag));
8480  config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag));
8481  config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag));
8482  config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag));
8483  config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag));
8484  config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag));
8485  config->SetMarker_All_Turbomachinery(iMarker, config->GetMarker_CfgFile_Turbomachinery(Marker_Tag));
8486  config->SetMarker_All_TurbomachineryFlag(iMarker, config->GetMarker_CfgFile_TurbomachineryFlag(Marker_Tag));
8487  config->SetMarker_All_MixingPlaneInterface(iMarker, config->GetMarker_CfgFile_MixingPlaneInterface(Marker_Tag));
8488  }
8489 
8490  /*--- Send-Receive boundaries definition ---*/
8491 
8492  else {
8493 
8494  config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE);
8495  config->SetMarker_All_Monitoring(iMarker, NO);
8496  config->SetMarker_All_GeoEval(iMarker, NO);
8497  config->SetMarker_All_Designing(iMarker, NO);
8498  config->SetMarker_All_Plotting(iMarker, NO);
8499  config->SetMarker_All_Analyze(iMarker, NO);
8500  config->SetMarker_All_ZoneInterface(iMarker, NO);
8501  config->SetMarker_All_DV(iMarker, NO);
8502  config->SetMarker_All_Moving(iMarker, NO);
8503  config->SetMarker_All_PyCustom(iMarker, NO);
8504  config->SetMarker_All_PerBound(iMarker, NO);
8505  config->SetMarker_All_Turbomachinery(iMarker, NO);
8506  config->SetMarker_All_TurbomachineryFlag(iMarker, NO);
8507  config->SetMarker_All_MixingPlaneInterface(iMarker, NO);
8508 
8509  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
8510  if (config->GetMarker_All_SendRecv(iMarker) < 0)
8511  node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false);
8512  }
8513 
8514  }
8515 
8516  /*--- Loop over the surface element to set the boundaries ---*/
8517 
8518  unsigned long Point_Surface, iElem_Surface;
8519  unsigned short iNode_Surface;
8520 
8521  for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) {
8522  for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) {
8523  Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface);
8524  node[Point_Surface]->SetBoundary(nMarker);
8525  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE &&
8526  config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY &&
8527  config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY &&
8528  config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)
8529  node[Point_Surface]->SetPhysicalBoundary(true);
8530 
8531  if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ||
8532  config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ||
8533  config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ||
8534  config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION)
8535  node[Point_Surface]->SetSolidBoundary(true);
8536  }
8537  }
8538 
8539  }
8540 
8541  delete [] Marker_All_SendRecv_Copy;
8542  delete [] nElem_Bound_Copy;
8543 }
8544 
8545 void CPhysicalGeometry::Read_SU2_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) {
8546 
8547  string text_line, Marker_Tag;
8548  ifstream mesh_file;
8549  unsigned short nMarker_Max = config->GetnMarker_Max();
8550  unsigned long VTK_Type, iMarker, iChar;
8551  unsigned long iCount = 0;
8552  unsigned long iElem_Bound = 0, iPoint = 0, ielem = 0;
8553  unsigned long vnodes_edge[2], vnodes_triangle[3], vnodes_quad[4];
8554  unsigned long vnodes_tetra[4], vnodes_hexa[8], vnodes_prism[6],
8555  vnodes_pyramid[5], dummyLong, GlobalIndex, LocalIndex;
8556  unsigned long i;
8557  long local_index;
8558  vector<unsigned long>::iterator it;
8559  char cstr[200];
8560  su2double Coord_2D[2], Coord_3D[3], AoA_Offset, AoS_Offset, AoA_Current, AoS_Current;
8561  string::size_type position;
8562  bool domain_flag = false;
8563  bool found_transform = false;
8564  bool harmonic_balance = config->GetUnsteady_Simulation() == HARMONIC_BALANCE;
8565  bool actuator_disk = (((config->GetnMarker_ActDiskInlet() != 0) ||
8566  (config->GetnMarker_ActDiskOutlet() != 0)) &&
8567  ((config->GetKind_SU2() == SU2_CFD) ||
8568  ((config->GetKind_SU2() == SU2_DEF) && (config->GetActDisk_SU2_DEF()))));
8569  if (config->GetActDisk_DoubleSurface()) actuator_disk = false;
8570 
8571  nZone = val_nZone;
8572 
8573  /*--- Initialize some additional counters for the parallel partitioning ---*/
8574 
8575  unsigned long total_pt_accounted = 0;
8576  unsigned long rem_points = 0;
8577  unsigned long element_count = 0;
8578  unsigned long boundary_marker_count = 0;
8579  unsigned long node_count = 0;
8580  unsigned long local_element_count = 0;
8581 
8582  /*--- Initialize counters for local/global points & elements ---*/
8583 
8584 #ifdef HAVE_MPI
8585  unsigned long j;
8586 #endif
8587 
8588  /*--- Actuator disk preprocesing ---*/
8589 
8590  string Marker_Tag_Duplicate;
8591  bool *ActDisk_Bool = NULL, *MapVolumePointBool = NULL, InElem, Perimeter;
8592  unsigned long *ActDiskPoint_Back = NULL, *VolumePoint_Inv = NULL, *ActDiskPoint_Front_Inv = NULL, ActDiskNewPoints = 0, Counter = 0;
8593  su2double *CoordXActDisk = NULL, *CoordYActDisk = NULL, *CoordZActDisk = NULL;
8594  su2double *CoordXVolumePoint = NULL, *CoordYVolumePoint = NULL, *CoordZVolumePoint = NULL;
8595  su2double Xloc = 0.0, Yloc = 0.0, Zloc = 0.0, Xcg = 0.0;
8596  unsigned long nElem_Bound_, kPoint;
8597 
8598  vector<unsigned long long> EdgeBegin, EdgeEnd;
8599 
8600  unsigned long AuxEdge, iEdge, jEdge, nEdges, nPointVolume, iElem;
8601  unsigned long long FirstEdgeIndex, SecondEdgeIndex;
8602 
8603  vector<unsigned long> ActDiskPoint_Front, VolumePoint, PerimeterPoint;
8604 
8605  /*--- If actuator disk, we should split the surface, the first step is to identify the existing boundary ---*/
8606 
8607  if (actuator_disk) {
8608 
8609  /*--- Open grid file ---*/
8610 
8611  strcpy (cstr, val_mesh_filename.c_str());
8612  mesh_file.open(cstr, ios::in);
8613 
8614  /*--- Check the grid ---*/
8615 
8616  if (mesh_file.fail()) {
8617  SU2_MPI::Error("There is no mesh file!!", CURRENT_FUNCTION);
8618  }
8619 
8620  /*--- Read grid file with format SU2 ---*/
8621 
8622  while (getline (mesh_file, text_line)) {
8623 
8624  position = text_line.find ("NDIME=",0);
8625  if (position != string::npos) {
8626  text_line.erase (0,6); nDim = atoi(text_line.c_str());
8627  }
8628 
8629  position = text_line.find ("NPOIN=",0);
8630  if (position != string::npos) {
8631  text_line.erase (0,6); stringstream test_line(text_line);
8632  iCount = 0; while (test_line >> dummyLong) iCount++;
8633  stringstream stream_line(text_line);
8634  if (iCount == 2) { stream_line >> nPoint; stream_line >> nPointDomain; }
8635  else if (iCount == 1) { stream_line >> nPoint; }
8636  for (iPoint = 0; iPoint < nPoint; iPoint++) getline (mesh_file, text_line);
8637  }
8638 
8639  position = text_line.find ("NELEM=",0);
8640  if (position != string::npos) {
8641  text_line.erase (0,6); nElem = atoi(text_line.c_str());
8642  for (iElem = 0; iElem < nElem; iElem++) getline (mesh_file, text_line);
8643  }
8644 
8645  position = text_line.find ("NMARK=",0);
8646  if (position != string::npos) {
8647  text_line.erase (0,6); nMarker = atoi(text_line.c_str());
8648 
8649  for (iMarker = 0 ; iMarker < nMarker; iMarker++) {
8650 
8651  getline (mesh_file, text_line);
8652  text_line.erase (0,11); string::size_type position;
8653  for (iChar = 0; iChar < 20; iChar++) {
8654  position = text_line.find( " ", 0 ); if (position != string::npos) text_line.erase (position,1);
8655  position = text_line.find( "\r", 0 ); if (position != string::npos) text_line.erase (position,1);
8656  position = text_line.find( "\n", 0 ); if (position != string::npos) text_line.erase (position,1);
8657  }
8658  Marker_Tag = text_line.c_str();
8659 
8660  getline (mesh_file, text_line);
8661  text_line.erase (0,13); nElem_Bound_ = atoi(text_line.c_str());
8662 
8663  if (( Marker_Tag == config->GetMarker_ActDiskInlet_TagBound(0)) && (rank == MASTER_NODE))
8664  cout << "Splitting the surface " << Marker_Tag << "( " << nElem_Bound_ << " boundary elements )." << endl;
8665 
8666  if (Marker_Tag != config->GetMarker_ActDiskInlet_TagBound(0)) {
8667  for (iElem_Bound = 0; iElem_Bound < nElem_Bound_; iElem_Bound++) { getline (mesh_file, text_line); }
8668  }
8669  else {
8670 
8671  /*--- Create a list of edges ---*/
8672 
8673  for (iElem_Bound = 0; iElem_Bound < nElem_Bound_; iElem_Bound++) {
8674 
8675  getline(mesh_file, text_line);
8676 
8677  istringstream bound_line(text_line); bound_line >> VTK_Type;
8678 
8679  switch(VTK_Type) {
8680  case LINE:
8681  bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1];
8682  EdgeBegin.push_back(vnodes_edge[0]); EdgeEnd.push_back(vnodes_edge[1]);
8683  break;
8684  case TRIANGLE:
8685  bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2];
8686  EdgeBegin.push_back(vnodes_triangle[0]); EdgeEnd.push_back(vnodes_triangle[1]);
8687  EdgeBegin.push_back(vnodes_triangle[1]); EdgeEnd.push_back(vnodes_triangle[2]);
8688  EdgeBegin.push_back(vnodes_triangle[2]); EdgeEnd.push_back(vnodes_triangle[0]);
8689  break;
8690  case QUADRILATERAL:
8691  bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3];
8692  EdgeBegin.push_back(vnodes_quad[0]); EdgeEnd.push_back(vnodes_quad[1]);
8693  EdgeBegin.push_back(vnodes_quad[1]); EdgeEnd.push_back(vnodes_quad[2]);
8694  EdgeBegin.push_back(vnodes_quad[2]); EdgeEnd.push_back(vnodes_quad[3]);
8695  EdgeBegin.push_back(vnodes_quad[3]); EdgeEnd.push_back(vnodes_quad[0]);
8696  break;
8697  }
8698 
8699  }
8700 
8701  /*--- Set the total number of edges ---*/
8702 
8703  nEdges = EdgeBegin.size();
8704 
8705  /*--- Sort edges based on local point index, first index is always the largest ---*/
8706 
8707  for (iEdge = 0; iEdge < nEdges; iEdge++) {
8708  if (EdgeEnd[iEdge] < EdgeBegin[iEdge]) {
8709  AuxEdge = EdgeEnd[iEdge]; EdgeEnd[iEdge] = EdgeBegin[iEdge]; EdgeBegin[iEdge] = AuxEdge;
8710  }
8711  }
8712 
8713  /*--- Bubble sort of the points based on the first index ---*/
8714 
8715  for (iEdge = 0; iEdge < nEdges; iEdge++) {
8716  for (jEdge = iEdge+1; jEdge < nEdges; jEdge++) {
8717 
8718  FirstEdgeIndex = EdgeBegin[jEdge] << 31;
8719  FirstEdgeIndex += EdgeEnd[jEdge];
8720 
8721  SecondEdgeIndex = EdgeBegin[iEdge] << 31;
8722  SecondEdgeIndex += EdgeEnd[iEdge];
8723 
8724  if (FirstEdgeIndex <= SecondEdgeIndex) {
8725  AuxEdge = EdgeBegin[iEdge]; EdgeBegin[iEdge] = EdgeBegin[jEdge]; EdgeBegin[jEdge] = AuxEdge;
8726  AuxEdge = EdgeEnd[iEdge]; EdgeEnd[iEdge] = EdgeEnd[jEdge]; EdgeEnd[jEdge] = AuxEdge;
8727  }
8728  }
8729  }
8730 
8731  if (nDim == 3) {
8732 
8733  /*--- Check the begning of the list ---*/
8734 
8735  if (!((EdgeBegin[0] == EdgeBegin[1]) && (EdgeEnd[0] == EdgeEnd[1]))) {
8736  PerimeterPoint.push_back(EdgeBegin[0]);
8737  PerimeterPoint.push_back(EdgeEnd[0]);
8738  }
8739 
8740  for (iEdge = 1; iEdge < nEdges-1; iEdge++) {
8741  bool Check_1 = !((EdgeBegin[iEdge] == EdgeBegin[iEdge-1]) && (EdgeEnd[iEdge] == EdgeEnd[iEdge-1]));
8742  bool Check_2 = !((EdgeBegin[iEdge] == EdgeBegin[iEdge+1]) && (EdgeEnd[iEdge] == EdgeEnd[iEdge+1]));
8743  if ((Check_1 && Check_2)) {
8744  PerimeterPoint.push_back(EdgeBegin[iEdge]);
8745  PerimeterPoint.push_back(EdgeEnd[iEdge]);
8746  }
8747  }
8748 
8749  /*--- Check the end of the list ---*/
8750 
8751  if (!((EdgeBegin[nEdges-1] == EdgeBegin[nEdges-2]) && (EdgeEnd[nEdges-1] == EdgeEnd[nEdges-2]))) {
8752  PerimeterPoint.push_back(EdgeBegin[nEdges-1]);
8753  PerimeterPoint.push_back(EdgeEnd[nEdges-1]);
8754  }
8755 
8756  }
8757 
8758  else {
8759 
8760 
8761  /*--- Create a list with all the points ---*/
8762 
8763  for (iEdge = 0; iEdge < nEdges; iEdge++) {
8764  ActDiskPoint_Front.push_back(EdgeBegin[iEdge]);
8765  ActDiskPoint_Front.push_back(EdgeEnd[iEdge]);
8766  }
8767 
8768  sort(ActDiskPoint_Front.begin(), ActDiskPoint_Front.end());
8769  it = unique(ActDiskPoint_Front.begin(), ActDiskPoint_Front.end());
8770  ActDiskPoint_Front.resize(it - ActDiskPoint_Front.begin());
8771 
8772  /*--- Check the begning of the list ---*/
8773 
8774  if (!(ActDiskPoint_Front[0] == ActDiskPoint_Front[1]) ) { PerimeterPoint.push_back(ActDiskPoint_Front[0]); }
8775 
8776  for (iPoint = 1; iPoint < ActDiskPoint_Front.size()-1; iPoint++) {
8777  bool Check_1 = !((ActDiskPoint_Front[iPoint] == ActDiskPoint_Front[iPoint-1]) );
8778  bool Check_2 = !((ActDiskPoint_Front[iPoint] == ActDiskPoint_Front[iPoint+1]) );
8779  if ((Check_1 && Check_2)) { PerimeterPoint.push_back(ActDiskPoint_Front[iEdge]); }
8780  }
8781 
8782  /*--- Check the end of the list ---*/
8783 
8784  if (!((EdgeBegin[ActDiskPoint_Front.size()-1] == EdgeBegin[ActDiskPoint_Front.size()-2]) )) {
8785  PerimeterPoint.push_back(ActDiskPoint_Front[ActDiskPoint_Front.size()-1]);
8786  }
8787 
8788  ActDiskPoint_Front.clear();
8789 
8790  }
8791 
8792  sort(PerimeterPoint.begin(), PerimeterPoint.end());
8793  it = unique(PerimeterPoint.begin(), PerimeterPoint.end());
8794  PerimeterPoint.resize(it - PerimeterPoint.begin());
8795 
8796  for (iEdge = 0; iEdge < nEdges; iEdge++) {
8797 
8798  Perimeter = false;
8799  for (iPoint = 0; iPoint < PerimeterPoint.size(); iPoint++) {
8800  if (EdgeBegin[iEdge] == PerimeterPoint[iPoint]) {
8801  Perimeter = true; break;
8802  }
8803  }
8804 
8805  if (!Perimeter) ActDiskPoint_Front.push_back(EdgeBegin[iEdge]);
8806 
8807  Perimeter = false;
8808  for (iPoint = 0; iPoint < PerimeterPoint.size(); iPoint++) {
8809  if (EdgeEnd[iEdge] == PerimeterPoint[iPoint]) {
8810  Perimeter = true; break;
8811  }
8812  }
8813 
8814  if (!Perimeter) ActDiskPoint_Front.push_back(EdgeEnd[iEdge]);
8815 
8816  }
8817 
8818  /*--- Sort, and remove repeated points from the disk list of points ---*/
8819 
8820  sort(ActDiskPoint_Front.begin(), ActDiskPoint_Front.end());
8821  it = unique(ActDiskPoint_Front.begin(), ActDiskPoint_Front.end());
8822  ActDiskPoint_Front.resize(it - ActDiskPoint_Front.begin());
8823  ActDiskNewPoints = ActDiskPoint_Front.size();
8824 
8825  if (rank == MASTER_NODE)
8826  cout << "Splitting the surface " << Marker_Tag << "( " << ActDiskPoint_Front.size() << " internal points )." << endl;
8827 
8828  /*--- Create a map from original point to the new ones (back plane) ---*/
8829 
8830  ActDiskPoint_Back = new unsigned long [nPoint];
8831  ActDisk_Bool = new bool [nPoint];
8832  ActDiskPoint_Front_Inv= new unsigned long [nPoint];
8833 
8834  for (iPoint = 0; iPoint < nPoint; iPoint++) {
8835  ActDisk_Bool[iPoint] = false;
8836  ActDiskPoint_Back[iPoint] = 0;
8837  }
8838 
8839  kPoint = nPoint;
8840  for (iPoint = 0; iPoint < ActDiskPoint_Front.size(); iPoint++) {
8841  ActDiskPoint_Front_Inv[ActDiskPoint_Front[iPoint]] = iPoint;
8842  ActDisk_Bool[ActDiskPoint_Front[iPoint]] = true;
8843  ActDiskPoint_Back[ActDiskPoint_Front[iPoint]] = kPoint;
8844  kPoint++;
8845  }
8846 
8847  }
8848  }
8849  }
8850  }
8851 
8852  mesh_file.close();
8853 
8854  /*--- Store the coordinates of the new points ---*/
8855 
8856  CoordXActDisk = new su2double[ActDiskNewPoints];
8857  CoordYActDisk = new su2double[ActDiskNewPoints];
8858  CoordZActDisk = new su2double[ActDiskNewPoints];
8859 
8860  strcpy (cstr, val_mesh_filename.c_str());
8861  mesh_file.open(cstr, ios::in);
8862 
8863 
8864  /*--- Read the coordinates of the points ---*/
8865 
8866  while (getline (mesh_file, text_line)) {
8867 
8868  position = text_line.find ("NPOIN=",0);
8869  if (position != string::npos) {
8870  text_line.erase (0,6); stringstream test_line(text_line);
8871  iCount = 0; while (test_line >> dummyLong) iCount++;
8872  stringstream stream_line(text_line);
8873  if (iCount == 2) { stream_line >> nPoint; stream_line >> nPointDomain; }
8874  else if (iCount == 1) { stream_line >> nPoint; }
8875 
8876  Counter = 0;
8877  for (iPoint = 0; iPoint < nPoint; iPoint++) {
8878  getline (mesh_file, text_line);
8879  istringstream point_line(text_line);
8880  if (nDim == 2) {point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; }
8881  else { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; }
8882 
8883  /*--- Compute the CG of the actuator disk surface ---*/
8884 
8885  if (ActDisk_Bool[iPoint]) {
8886  CoordXActDisk[ActDiskPoint_Front_Inv[iPoint]] = Coord_3D[0];
8887  CoordYActDisk[ActDiskPoint_Front_Inv[iPoint]] = Coord_3D[1];
8888  Xloc += Coord_3D[0]; Yloc += Coord_3D[1];
8889  if (nDim == 3) {
8890  CoordZActDisk[ActDiskPoint_Front_Inv[iPoint]] = Coord_3D[2];
8891  Zloc += Coord_3D[2];
8892  }
8893  Counter++;
8894  }
8895 
8896  }
8897  }
8898 
8899  /*--- Find points that touch the actuator disk surface ---*/
8900 
8901  position = text_line.find ("NELEM=",0);
8902  if (position != string::npos) {
8903  text_line.erase (0,6); nElem = atol(text_line.c_str());
8904  for (iElem = 0; iElem < nElem; iElem++) {
8905 
8906  getline(mesh_file, text_line);
8907  istringstream elem_line(text_line);
8908 
8909  elem_line >> VTK_Type;
8910 
8911  switch(VTK_Type) {
8912  case TRIANGLE:
8913  elem_line >> vnodes_triangle[0]; elem_line >> vnodes_triangle[1]; elem_line >> vnodes_triangle[2];
8914  InElem = false;
8915  for (i = 0; i < (unsigned long)N_POINTS_TRIANGLE; i++) {
8916  if (ActDisk_Bool[vnodes_triangle[i]]) { InElem = true; break; } }
8917  if (InElem) {
8918  for (i = 0; i < (unsigned long)N_POINTS_TRIANGLE; i++) {
8919  VolumePoint.push_back(vnodes_triangle[i]); } }
8920  break;
8921  case QUADRILATERAL:
8922  elem_line >> vnodes_quad[0]; elem_line >> vnodes_quad[1]; elem_line >> vnodes_quad[2]; elem_line >> vnodes_quad[3];
8923  InElem = false;
8924  for (i = 0; i < (unsigned long)N_POINTS_QUADRILATERAL; i++) {
8925  if (ActDisk_Bool[vnodes_quad[i]]) { InElem = true; break; } }
8926  if (InElem) {
8927  for (i = 0; i < (unsigned long)N_POINTS_QUADRILATERAL; i++) {
8928  VolumePoint.push_back(vnodes_quad[i]); } }
8929  break;
8930  case TETRAHEDRON:
8931  elem_line >> vnodes_tetra[0]; elem_line >> vnodes_tetra[1]; elem_line >> vnodes_tetra[2]; elem_line >> vnodes_tetra[3];
8932  InElem = false;
8933  for (i = 0; i < (unsigned long)N_POINTS_TETRAHEDRON; i++) {
8934  if (ActDisk_Bool[vnodes_tetra[i]]) { InElem = true; break; } }
8935  if (InElem) {
8936  for (i = 0; i < (unsigned long)N_POINTS_TETRAHEDRON; i++) {
8937  VolumePoint.push_back(vnodes_tetra[i]); } }
8938  break;
8939  case HEXAHEDRON:
8940  elem_line >> vnodes_hexa[0]; elem_line >> vnodes_hexa[1]; elem_line >> vnodes_hexa[2];
8941  elem_line >> vnodes_hexa[3]; elem_line >> vnodes_hexa[4]; elem_line >> vnodes_hexa[5];
8942  elem_line >> vnodes_hexa[6]; elem_line >> vnodes_hexa[7];
8943  InElem = false;
8944  for (i = 0; i < (unsigned long)N_POINTS_HEXAHEDRON; i++) {
8945  if (ActDisk_Bool[vnodes_hexa[i]]) { InElem = true; break; } }
8946  if (InElem) {
8947  for (i = 0; i < (unsigned long)N_POINTS_HEXAHEDRON; i++) {
8948  VolumePoint.push_back(vnodes_hexa[i]); } }
8949  break;
8950  case PRISM:
8951  elem_line >> vnodes_prism[0]; elem_line >> vnodes_prism[1]; elem_line >> vnodes_prism[2];
8952  elem_line >> vnodes_prism[3]; elem_line >> vnodes_prism[4]; elem_line >> vnodes_prism[5];
8953  InElem = false;
8954  for (i = 0; i < (unsigned long)N_POINTS_PRISM; i++) {
8955  if (ActDisk_Bool[vnodes_prism[i]]) { InElem = true; break; } }
8956  if (InElem) {
8957  for (i = 0; i < (unsigned long)N_POINTS_PRISM; i++) {
8958  VolumePoint.push_back(vnodes_prism[i]); } }
8959  break;
8960  case PYRAMID:
8961  elem_line >> vnodes_pyramid[0]; elem_line >> vnodes_pyramid[1]; elem_line >> vnodes_pyramid[2];
8962  elem_line >> vnodes_pyramid[3]; elem_line >> vnodes_pyramid[4];
8963  InElem = false;
8964  for (i = 0; i < (unsigned long)N_POINTS_PYRAMID; i++) {
8965  if (ActDisk_Bool[vnodes_pyramid[i]]) { InElem = true; break; } }
8966  if (InElem) {
8967  for (i = 0; i < (unsigned long)N_POINTS_PYRAMID; i++) {
8968  VolumePoint.push_back(vnodes_pyramid[i]); } }
8969  break;
8970  }
8971  }
8972  }
8973 
8974  }
8975 
8976  mesh_file.close();
8977 
8978  /*--- Compute the CG of the surface ---*/
8979 
8980  Xloc /= su2double(Counter); Yloc /= su2double(Counter); Zloc /= su2double(Counter);
8981 
8982  /*--- Sort,and remove repeated points from the disk list of points ---*/
8983 
8984  sort(VolumePoint.begin(), VolumePoint.end());
8985  it = unique(VolumePoint.begin(), VolumePoint.end());
8986  VolumePoint.resize(it - VolumePoint.begin());
8987  nPointVolume = VolumePoint.size();
8988 
8989 
8990  CoordXVolumePoint = new su2double[nPointVolume];
8991  CoordYVolumePoint = new su2double[nPointVolume];
8992  CoordZVolumePoint = new su2double[nPointVolume];
8993  MapVolumePointBool = new bool[nPoint];
8994  VolumePoint_Inv = new unsigned long[nPoint];
8995 
8996  for (iPoint = 0; iPoint < nPoint; iPoint++) {
8997  MapVolumePointBool[iPoint] = false;
8998  }
8999 
9000  for (iPoint = 0; iPoint < nPointVolume; iPoint++) {
9001  MapVolumePointBool[VolumePoint[iPoint]] = true;
9002  VolumePoint_Inv[VolumePoint[iPoint]] = iPoint;
9003  }
9004 
9005  strcpy (cstr, val_mesh_filename.c_str());
9006  mesh_file.open(cstr, ios::in);
9007 
9008  /*--- Store the coordinates of all the surface and volume
9009  points that touch the actuator disk ---*/
9010 
9011  while (getline (mesh_file, text_line)) {
9012 
9013  position = text_line.find ("NPOIN=",0);
9014  if (position != string::npos) {
9015  text_line.erase (0,6); stringstream test_line(text_line);
9016  iCount = 0; while (test_line >> dummyLong) iCount++;
9017  stringstream stream_line(text_line);
9018  if (iCount == 2) { stream_line >> nPoint; stream_line >> nPointDomain; }
9019  else if (iCount == 1) { stream_line >> nPoint; }
9020 
9021  Counter =0;
9022  for (iPoint = 0; iPoint < nPoint; iPoint++) {
9023  getline (mesh_file, text_line);
9024  istringstream point_line(text_line);
9025  if (nDim == 2) {point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; }
9026  else { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; }
9027 
9028  if (MapVolumePointBool[iPoint]) {
9029  CoordXVolumePoint[VolumePoint_Inv[iPoint]] = Coord_3D[0];
9030  CoordYVolumePoint[VolumePoint_Inv[iPoint]] = Coord_3D[1];
9031  if (nDim == 3) { CoordZVolumePoint[VolumePoint_Inv[iPoint]] = Coord_3D[2]; }
9032  }
9033  }
9034  }
9035 
9036  }
9037 
9038  mesh_file.close();
9039 
9040  /*--- Deallocate memory ---*/
9041 
9042  delete [] MapVolumePointBool;
9043  delete [] ActDiskPoint_Front_Inv;
9044 
9045  // }
9046 
9047  // /*--- Allocate and Send-Receive some of the vectors that we have computed on the MASTER_NODE ---*/
9048 
9049  // SU2_MPI::Bcast(&ActDiskNewPoints, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD);
9050  // SU2_MPI::Bcast(&nPoint, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD);
9051  // SU2_MPI::Bcast(&nPointVolume, 1, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD);
9052  // SU2_MPI::Bcast(&Xloc, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9053  // SU2_MPI::Bcast(&Yloc, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9054  // SU2_MPI::Bcast(&Zloc, 1, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9055 
9056  // if (rank != MASTER_NODE) {
9057  // MapActDisk = new unsigned long [nPoint];
9058  // ActDisk_Bool = new bool [nPoint];
9059  // VolumePoint_Inv = new unsigned long [nPoint];
9060  // CoordXVolumePoint = new su2double [nPointVolume];
9061  // CoordYVolumePoint = new su2double [nPointVolume];
9062  // CoordZVolumePoint = new su2double [nPointVolume];
9063  // CoordXActDisk = new su2double[ActDiskNewPoints];
9064  // CoordYActDisk = new su2double[ActDiskNewPoints];
9065  // CoordZActDisk = new su2double[ActDiskNewPoints];
9066  // }
9067 
9068  // SU2_MPI::Bcast(MapActDisk, nPoint, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD);
9069  // SU2_MPI::Bcast(ActDisk_Bool, nPoint, MPI_UNSIGNED_SHORT, MASTER_NODE, MPI_COMM_WORLD);
9070  // SU2_MPI::Bcast(VolumePoint_Inv, nPoint, MPI_UNSIGNED_LONG, MASTER_NODE, MPI_COMM_WORLD);
9071  // SU2_MPI::Bcast(CoordXVolumePoint, nPointVolume, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9072  // SU2_MPI::Bcast(CoordYVolumePoint, nPointVolume, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9073  // SU2_MPI::Bcast(CoordZVolumePoint, nPointVolume, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9074  // SU2_MPI::Bcast(CoordXActDisk, ActDiskNewPoints, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9075  // SU2_MPI::Bcast(CoordYActDisk, ActDiskNewPoints, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9076  // SU2_MPI::Bcast(CoordZActDisk, ActDiskNewPoints, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
9077 
9078  }
9079 
9081  nelem_edge = 0; Global_nelem_edge = 0;
9083  nelem_quad = 0; Global_nelem_quad = 0;
9085  nelem_hexa = 0; Global_nelem_hexa = 0;
9088 
9089  /*--- Allocate memory for the linear partition of the mesh. These
9090  arrays are the size of the number of ranks. ---*/
9091 
9092  starting_node = new unsigned long[size];
9093  ending_node = new unsigned long[size];
9094  npoint_procs = new unsigned long[size];
9095  nPoint_Linear = new unsigned long[size+1];
9096 
9097  /*--- Open grid file ---*/
9098 
9099  strcpy (cstr, val_mesh_filename.c_str());
9100  mesh_file.open(cstr, ios::in);
9101 
9102  /*--- Check the grid ---*/
9103 
9104  if (mesh_file.fail()) {
9105  SU2_MPI::Error("There is no mesh file!!", CURRENT_FUNCTION);
9106  }
9107 
9108  /*--- If more than one, find the zone in the mesh file ---*/
9109 
9110  if (val_nZone > 1 || harmonic_balance) {
9111  if (harmonic_balance) {
9112  if (rank == MASTER_NODE) cout << "Reading time instance " << config->GetiInst()+1 << "." << endl;
9113  } else {
9114  while (getline (mesh_file,text_line)) {
9115  /*--- Search for the current domain ---*/
9116  position = text_line.find ("IZONE=",0);
9117  if (position != string::npos) {
9118  text_line.erase (0,6);
9119  unsigned short jDomain = atoi(text_line.c_str());
9120  if (jDomain == val_iZone+1) {
9121  if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone+1 << "." << endl;
9122  break;
9123  }
9124  }
9125  }
9126  }
9127  }
9128 
9129  /*--- Read grid file with format SU2 ---*/
9130 
9131  while (getline (mesh_file, text_line)) {
9132 
9133  /*--- Read the dimension of the problem ---*/
9134 
9135  position = text_line.find ("NDIME=",0);
9136  if (position != string::npos) {
9137  if (domain_flag == false) {
9138  text_line.erase (0,6); nDim = atoi(text_line.c_str());
9139  if (rank == MASTER_NODE) {
9140  if (nDim == 2) cout << "Two dimensional problem." << endl;
9141  if (nDim == 3) cout << "Three dimensional problem." << endl;
9142  }
9143  domain_flag = true;
9144  } else { break; }
9145  }
9146 
9147  /*--- Read if there is any offset in the mesh parameters ---*/
9148 
9149  position = text_line.find ("AOA_OFFSET=",0);
9150  if (position != string::npos) {
9151  AoA_Offset = 0.0;
9152  text_line.erase (0,11); AoA_Offset = atof(text_line.c_str());
9153 
9154  /*--- The offset is in deg ---*/
9155 
9156  AoA_Current = config->GetAoA() + AoA_Offset;
9157 
9158  if (config->GetDiscard_InFiles() == false) {
9159  if ((rank == MASTER_NODE) && (AoA_Offset != 0.0)) {
9160  cout.precision(6);
9161  cout << fixed <<"WARNING: AoA in the config file (" << config->GetAoA() << " deg.) +" << endl;
9162  cout << " AoA offset in mesh file (" << AoA_Offset << " deg.) = " << AoA_Current << " deg." << endl;
9163  }
9164  config->SetAoA_Offset(AoA_Offset);
9165  config->SetAoA(AoA_Current);
9166  }
9167  else {
9168  if ((rank == MASTER_NODE) && (AoA_Offset != 0.0))
9169  cout <<"WARNING: Discarding the AoA offset in the geometry file." << endl;
9170  }
9171 
9172  }
9173 
9174  position = text_line.find ("AOS_OFFSET=",0);
9175  if (position != string::npos) {
9176  AoS_Offset = 0.0;
9177  text_line.erase (0,11); AoS_Offset = atof(text_line.c_str());
9178 
9179  /*--- The offset is in deg ---*/
9180 
9181  AoS_Current = config->GetAoS() + AoS_Offset;
9182 
9183  if (config->GetDiscard_InFiles() == false) {
9184  if ((rank == MASTER_NODE) && (AoS_Offset != 0.0)) {
9185  cout.precision(6);
9186  cout << fixed <<"WARNING: AoS in the config file (" << config->GetAoS() << " deg.) +" << endl;
9187  cout << " AoS offset in mesh file (" << AoS_Offset << " deg.) = " << AoS_Current << " deg." << endl;
9188  }
9189  config->SetAoS_Offset(AoS_Offset);
9190  config->SetAoS(AoS_Current);
9191  }
9192  else {
9193  if ((rank == MASTER_NODE) && (AoS_Offset != 0.0))
9194  cout <<"WARNING: Discarding the AoS offset in the geometry file." << endl;
9195  }
9196 
9197  }
9198 
9199  /*--- Read number of points ---*/
9200 
9201  position = text_line.find ("NPOIN=",0);
9202  if (position != string::npos) {
9203  text_line.erase (0,6);
9204 
9205  /*--- Check for ghost points. ---*/
9206  stringstream test_line(text_line);
9207  iCount = 0; while (test_line >> dummyLong) iCount++;
9208 
9209  /*--- Now read and store the number of points and possible ghost points. ---*/
9210 
9211  stringstream stream_line(text_line);
9212  if (iCount == 2) {
9213 
9214  stream_line >> nPoint;
9215  stream_line >> nPointDomain;
9216 
9217  if (actuator_disk) { nPoint += ActDiskNewPoints; nPointDomain += ActDiskNewPoints; }
9218 
9219  /*--- Set some important point information for parallel simulations. ---*/
9220 
9223  if (rank == MASTER_NODE && size > SINGLE_NODE) {
9224  cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain;
9225  cout << " ghost points before parallel partitioning." << endl;
9226  } else if (rank == MASTER_NODE) {
9227  cout << Global_nPointDomain << " points and " << Global_nPoint-Global_nPointDomain;
9228  cout << " ghost points." << endl;
9229  }
9230 
9231  } else if (iCount == 1) {
9232  stream_line >> nPoint;
9233 
9234  if (actuator_disk) { nPoint += ActDiskNewPoints; }
9235 
9236  nPointDomain = nPoint;
9239  if (rank == MASTER_NODE && size > SINGLE_NODE) {
9240  cout << nPoint << " points before parallel partitioning." << endl;
9241  } else if (rank == MASTER_NODE) {
9242  cout << nPoint << " points." << endl;
9243  }
9244  }
9245  else {
9246  SU2_MPI::Error("NPOIN improperly specified", CURRENT_FUNCTION);
9247  }
9248 
9249  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
9250  cout << "Performing linear partitioning of the grid nodes." << endl;
9251 
9252  /*--- Compute the number of points that will be on each processor.
9253  This is a linear partitioning with the addition of a simple load
9254  balancing for any remainder points. ---*/
9255 
9256  total_pt_accounted = 0;
9257  for (i = 0; i < (unsigned long)size; i++) {
9258  npoint_procs[i] = nPoint/size;
9259  total_pt_accounted = total_pt_accounted + npoint_procs[i];
9260  }
9261 
9262  /*--- Get the number of remainder points after the even division ---*/
9263 
9264  rem_points = nPoint-total_pt_accounted;
9265  for (i = 0; i<rem_points; i++) {
9266  npoint_procs[i]++;
9267  }
9268 
9269  /*--- Store the local number of nodes and the beginning/end index.
9270  nPoint is always used to store the local number of points. ---*/
9271 
9273  starting_node[0] = 0;
9274  ending_node[0] = starting_node[0] + npoint_procs[0];
9275  nPoint_Linear[0] = 0;
9276  for (unsigned long i = 1; i < (unsigned long)size; i++) {
9277  starting_node[i] = ending_node[i-1];
9278  ending_node[i] = starting_node[i] + npoint_procs[i];
9279  nPoint_Linear[i] = nPoint_Linear[i-1] + npoint_procs[i-1];
9280  }
9282 
9283  /*--- Here we check if a point in the mesh file lies in the domain
9284  and if so, then store it on the local processor. We only create enough
9285  space in the node container for the local nodes at this point. ---*/
9286 
9287  nPointNode = nPoint;
9288  node = new CPoint*[nPoint];
9289  iPoint = 0; node_count = 0;
9290  while (node_count < Global_nPoint) {
9291 
9292  if (!actuator_disk) { getline(mesh_file, text_line); }
9293  else {
9294  if (node_count < Global_nPoint-ActDiskNewPoints) {
9295  getline(mesh_file, text_line);
9296  }
9297  else {
9298  ostringstream strsX, strsY, strsZ;
9299  unsigned long BackActDisk_Index = node_count;
9300  LocalIndex = BackActDisk_Index - (Global_nPoint-ActDiskNewPoints);
9301  strsX.precision(20); strsY.precision(20); strsZ.precision(20);
9302  su2double CoordX = CoordXActDisk[LocalIndex]; strsX << scientific << CoordX;
9303  su2double CoordY = CoordYActDisk[LocalIndex]; strsY << scientific << CoordY;
9304  su2double CoordZ = CoordZActDisk[LocalIndex]; strsZ << scientific << CoordZ;
9305  text_line = strsX.str() + "\t" + strsY.str() + "\t" + strsZ.str();
9306  }
9307  }
9308 
9309  istringstream point_line(text_line);
9310 
9311  /*--- We only read information for this node if it is owned by this
9312  rank based upon our initial linear partitioning. ---*/
9313 
9314  if ((node_count >= starting_node[rank]) && (node_count < ending_node[rank])) {
9315  switch(nDim) {
9316  case 2:
9317  GlobalIndex = node_count;
9318 #ifndef HAVE_MPI
9319  point_line >> Coord_2D[0]; point_line >> Coord_2D[1];
9320 #else
9321  if (size > SINGLE_NODE) { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; GlobalIndex = node_count; }
9322  else { point_line >> Coord_2D[0]; point_line >> Coord_2D[1]; GlobalIndex = node_count; }
9323 #endif
9324  node[iPoint] = new CPoint(Coord_2D[0], Coord_2D[1], GlobalIndex, config);
9325  iPoint++; break;
9326  case 3:
9327  GlobalIndex = node_count;
9328 #ifndef HAVE_MPI
9329  point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2];
9330 #else
9331  if (size > SINGLE_NODE) { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; GlobalIndex = node_count; }
9332  else { point_line >> Coord_3D[0]; point_line >> Coord_3D[1]; point_line >> Coord_3D[2]; GlobalIndex = node_count; }
9333 #endif
9334  node[iPoint] = new CPoint(Coord_3D[0], Coord_3D[1], Coord_3D[2], GlobalIndex, config);
9335  iPoint++; break;
9336  }
9337  }
9338  node_count++;
9339  }
9340  }
9341  }
9342 
9343  mesh_file.close();
9344  strcpy (cstr, val_mesh_filename.c_str());
9345 
9346  /*--- Read the elements in the file with two loops. The first finds
9347  elements that live in the local partition and builds the adjacency
9348  for ParMETIS (if parallel). Once we know how many elements we have
9349  on the local partition, we allocate memory and store those elements. ---*/
9350 
9351  map<unsigned long,bool> ElemIn;
9352  map<unsigned long, bool>::const_iterator MI;
9353 #ifdef HAVE_MPI
9354 #ifdef HAVE_PARMETIS
9355  /*--- Initialize a vector for the adjacency information (ParMETIS). ---*/
9356  vector< vector<unsigned long> > adj_nodes(nPoint, vector<unsigned long>(0));
9357 #endif
9358 #endif
9359 
9360  /*--- Open the mesh file and find the section with the elements. ---*/
9361 
9362  mesh_file.open(cstr, ios::in);
9363 
9364  /*--- If more than one, find the zone in the mesh file ---*/
9365 
9366  if (val_nZone > 1) {
9367  while (getline (mesh_file,text_line)) {
9368  /*--- Search for the current domain ---*/
9369  position = text_line.find ("IZONE=",0);
9370  if (position != string::npos) {
9371  text_line.erase (0,6);
9372  unsigned short jDomain = atoi(text_line.c_str());
9373  if (jDomain == val_iZone+1) {
9374  break;
9375  }
9376  }
9377  }
9378  }
9379 
9380  while (getline (mesh_file, text_line)) {
9381 
9382  /*--- Read the information about inner elements ---*/
9383 
9384  position = text_line.find ("NELEM=",0);
9385  if (position != string::npos) {
9386  text_line.erase (0,6); nElem = atol(text_line.c_str());
9387 
9388  /*--- Store total number of elements in the original mesh ---*/
9389 
9390  Global_nElem = nElem;
9391  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
9392  cout << Global_nElem << " interior elements before parallel partitioning." << endl;
9393 
9394  /*--- Loop over all the volumetric elements and store any element that
9395  contains at least one of an owned node for this rank (i.e., there will
9396  be element redundancy, since multiple ranks will store the same elems
9397  on the boundaries of the initial linear partitioning. ---*/
9398 
9399  element_count = 0; local_element_count = 0;
9400  while (element_count < Global_nElem) {
9401  getline(mesh_file, text_line);
9402  istringstream elem_line(text_line);
9403 
9404  /*--- Decide whether this rank needs each element. If so, build the
9405  adjacency arrays needed by ParMETIS and store the element connectivity.
9406  Note that every proc starts it's node indexing from zero. ---*/
9407 
9408  elem_line >> VTK_Type;
9409  switch(VTK_Type) {
9410 
9411  case TRIANGLE:
9412 
9413  /*--- Load the connectivity for this element. ---*/
9414 
9415  elem_line >> vnodes_triangle[0];
9416  elem_line >> vnodes_triangle[1];
9417  elem_line >> vnodes_triangle[2];
9418 
9419  if (actuator_disk) {
9420  for (unsigned short i = 0; i<N_POINTS_TRIANGLE; i++) {
9421  if (ActDisk_Bool[vnodes_triangle[i]]) {
9422 
9423  Xcg = 0.0; Counter = 0;
9424  for (unsigned short j = 0; j<N_POINTS_TRIANGLE; j++) {
9425  if (vnodes_triangle[j] < Global_nPoint-ActDiskNewPoints) {
9426  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_triangle[j]]];
9427  Counter++;
9428  }
9429  }
9430  Xcg = Xcg / su2double(Counter);
9431 
9432  if (Counter != 0) {
9433  if (Xcg > Xloc) {
9434  vnodes_triangle[i] = ActDiskPoint_Back[vnodes_triangle[i]];
9435  }
9436  else { vnodes_triangle[i] = vnodes_triangle[i]; }
9437  }
9438 
9439  }
9440  }
9441  }
9442 
9443  /*--- Decide whether we need to store this element, i.e., check if
9444  any of the nodes making up this element have a global index value
9445  that falls within the range of our linear partitioning. ---*/
9446 
9447  for (unsigned short i = 0; i < N_POINTS_TRIANGLE; i++) {
9448 
9449  local_index = vnodes_triangle[i]-starting_node[rank];
9450 
9451  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9452 
9453  /*--- This node is within our linear partition. Mark this
9454  entire element to be added to our list for this rank, and
9455  add the neighboring nodes to this nodes' adjacency list. ---*/
9456 
9457  ElemIn[element_count] = true;
9458 
9459 #ifdef HAVE_MPI
9460 #ifdef HAVE_PARMETIS
9461  /*--- Build adjacency assuming the VTK connectivity ---*/
9462  for (unsigned short j=0; j<N_POINTS_TRIANGLE; j++) {
9463  if (i != j) adj_nodes[local_index].push_back(vnodes_triangle[j]);
9464  }
9465 #endif
9466 #endif
9467  }
9468  }
9469 
9470  MI = ElemIn.find(element_count);
9471  if (MI != ElemIn.end()) local_element_count++;
9472 
9473  break;
9474 
9475  case QUADRILATERAL:
9476 
9477  /*--- Load the connectivity for this element. ---*/
9478 
9479  elem_line >> vnodes_quad[0];
9480  elem_line >> vnodes_quad[1];
9481  elem_line >> vnodes_quad[2];
9482  elem_line >> vnodes_quad[3];
9483 
9484  if (actuator_disk) {
9485  for (unsigned short i = 0; i<N_POINTS_QUADRILATERAL; i++) {
9486  if (ActDisk_Bool[vnodes_quad[i]]) {
9487 
9488  Xcg = 0.0; Counter = 0;
9489  for (unsigned short j = 0; j<N_POINTS_QUADRILATERAL; j++) {
9490  if (vnodes_quad[j] < Global_nPoint-ActDiskNewPoints) {
9491  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_quad[j]]];
9492  Counter++;
9493  }
9494  }
9495  Xcg = Xcg / su2double(Counter);
9496 
9497 
9498  if (Counter != 0) {
9499  if (Xcg > Xloc) {
9500  vnodes_quad[i] = ActDiskPoint_Back[vnodes_quad[i]];
9501  }
9502  else { vnodes_quad[i] = vnodes_quad[i]; }
9503  }
9504 
9505  }
9506  }
9507  }
9508 
9509  /*--- Decide whether we need to store this element, i.e., check if
9510  any of the nodes making up this element have a global index value
9511  that falls within the range of our linear partitioning. ---*/
9512 
9513  for (unsigned short i = 0; i < N_POINTS_QUADRILATERAL; i++) {
9514 
9515  local_index = vnodes_quad[i]-starting_node[rank];
9516 
9517  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9518 
9519  /*--- This node is within our linear partition. Mark this
9520  entire element to be added to our list for this rank, and
9521  add the neighboring nodes to this nodes' adjacency list. ---*/
9522 
9523  ElemIn[element_count] = true;
9524 
9525 #ifdef HAVE_MPI
9526 #ifdef HAVE_PARMETIS
9527  /*--- Build adjacency assuming the VTK connectivity ---*/
9528  adj_nodes[local_index].push_back(vnodes_quad[(i+1)%4]);
9529  adj_nodes[local_index].push_back(vnodes_quad[(i+3)%4]);
9530 #endif
9531 #endif
9532  }
9533  }
9534 
9535  MI = ElemIn.find(element_count);
9536  if (MI != ElemIn.end()) local_element_count++;
9537 
9538  break;
9539 
9540  case TETRAHEDRON:
9541 
9542  /*--- Load the connectivity for this element. ---*/
9543 
9544  elem_line >> vnodes_tetra[0];
9545  elem_line >> vnodes_tetra[1];
9546  elem_line >> vnodes_tetra[2];
9547  elem_line >> vnodes_tetra[3];
9548 
9549  if (actuator_disk) {
9550  for (unsigned short i = 0; i<N_POINTS_TETRAHEDRON; i++) {
9551  if (ActDisk_Bool[vnodes_tetra[i]]) {
9552 
9553  Xcg = 0.0; Counter = 0;
9554  for (unsigned short j = 0; j<N_POINTS_TETRAHEDRON; j++) {
9555  if (vnodes_tetra[j] < Global_nPoint-ActDiskNewPoints) {
9556  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_tetra[j]]];
9557  Counter++;
9558  }
9559  }
9560  Xcg = Xcg / su2double(Counter);
9561 
9562 
9563  if (Counter != 0) {
9564  if (Xcg > Xloc) {
9565  vnodes_tetra[i] = ActDiskPoint_Back[vnodes_tetra[i]];
9566  }
9567  else { vnodes_tetra[i] = vnodes_tetra[i]; }
9568  }
9569 
9570  }
9571  }
9572  }
9573 
9574  /*--- Decide whether we need to store this element, i.e., check if
9575  any of the nodes making up this element have a global index value
9576  that falls within the range of our linear partitioning. ---*/
9577 
9578  for (unsigned short i = 0; i < N_POINTS_TETRAHEDRON; i++) {
9579 
9580  local_index = vnodes_tetra[i]-starting_node[rank];
9581 
9582  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9583 
9584  /*--- This node is within our linear partition. Mark this
9585  entire element to be added to our list for this rank, and
9586  add the neighboring nodes to this nodes' adjacency list. ---*/
9587 
9588  ElemIn[element_count] = true;
9589 
9590 #ifdef HAVE_MPI
9591 #ifdef HAVE_PARMETIS
9592  /*--- Build adjacency assuming the VTK connectivity ---*/
9593  for (unsigned short j=0; j<N_POINTS_TETRAHEDRON; j++) {
9594  if (i != j) adj_nodes[local_index].push_back(vnodes_tetra[j]);
9595  }
9596 #endif
9597 #endif
9598  }
9599  }
9600 
9601  MI = ElemIn.find(element_count);
9602  if (MI != ElemIn.end()) local_element_count++;
9603 
9604  break;
9605 
9606  case HEXAHEDRON:
9607 
9608  /*--- Load the connectivity for this element. ---*/
9609 
9610  elem_line >> vnodes_hexa[0];
9611  elem_line >> vnodes_hexa[1];
9612  elem_line >> vnodes_hexa[2];
9613  elem_line >> vnodes_hexa[3];
9614  elem_line >> vnodes_hexa[4];
9615  elem_line >> vnodes_hexa[5];
9616  elem_line >> vnodes_hexa[6];
9617  elem_line >> vnodes_hexa[7];
9618 
9619  if (actuator_disk) {
9620  for (unsigned short i = 0; i<N_POINTS_HEXAHEDRON; i++) {
9621  if (ActDisk_Bool[vnodes_hexa[i]]) {
9622 
9623  Xcg = 0.0; Counter = 0;
9624  for (unsigned short j = 0; j<N_POINTS_HEXAHEDRON; j++) {
9625  if (vnodes_hexa[j] < Global_nPoint-ActDiskNewPoints) {
9626  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_hexa[j]]];
9627  Counter++;
9628  }
9629  }
9630  Xcg = Xcg / su2double(Counter);
9631 
9632  if (Counter != 0) {
9633  if (Xcg > Xloc) { vnodes_hexa[i] = ActDiskPoint_Back[vnodes_hexa[i]]; }
9634  else { vnodes_hexa[i] = vnodes_hexa[i]; }
9635  }
9636  }
9637  }
9638  }
9639 
9640  /*--- Decide whether we need to store this element, i.e., check if
9641  any of the nodes making up this element have a global index value
9642  that falls within the range of our linear partitioning. ---*/
9643 
9644  for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) {
9645 
9646  local_index = vnodes_hexa[i]-starting_node[rank];
9647 
9648  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9649 
9650  /*--- This node is within our linear partition. Mark this
9651  entire element to be added to our list for this rank, and
9652  add the neighboring nodes to this nodes' adjacency list. ---*/
9653 
9654  ElemIn[element_count] = true;
9655 
9656 #ifdef HAVE_MPI
9657 #ifdef HAVE_PARMETIS
9658  /*--- Build adjacency assuming the VTK connectivity ---*/
9659  if (i < 4) {
9660  adj_nodes[local_index].push_back(vnodes_hexa[(i+1)%4]);
9661  adj_nodes[local_index].push_back(vnodes_hexa[(i+3)%4]);
9662  } else {
9663  adj_nodes[local_index].push_back(vnodes_hexa[(i-3)%4+4]);
9664  adj_nodes[local_index].push_back(vnodes_hexa[(i-1)%4+4]);
9665  }
9666  adj_nodes[local_index].push_back(vnodes_hexa[(i+4)%8]);
9667 #endif
9668 #endif
9669  }
9670  }
9671 
9672  MI = ElemIn.find(element_count);
9673  if (MI != ElemIn.end()) local_element_count++;
9674 
9675  break;
9676 
9677  case PRISM:
9678 
9679  /*--- Load the connectivity for this element. ---*/
9680 
9681  elem_line >> vnodes_prism[0];
9682  elem_line >> vnodes_prism[1];
9683  elem_line >> vnodes_prism[2];
9684  elem_line >> vnodes_prism[3];
9685  elem_line >> vnodes_prism[4];
9686  elem_line >> vnodes_prism[5];
9687 
9688  if (actuator_disk) {
9689  for (unsigned short i = 0; i<N_POINTS_PRISM; i++) {
9690  if (ActDisk_Bool[vnodes_prism[i]]) {
9691 
9692  Xcg = 0.0; Counter = 0;
9693  for (unsigned short j = 0; j<N_POINTS_PRISM; j++) {
9694  if (vnodes_prism[j] < Global_nPoint-ActDiskNewPoints) {
9695  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_prism[j]]];
9696  Counter++;
9697  }
9698  }
9699  Xcg = Xcg / su2double(Counter);
9700 
9701  if (Counter != 0) {
9702  if (Xcg > Xloc) { vnodes_prism[i] = ActDiskPoint_Back[vnodes_prism[i]]; }
9703  else { vnodes_prism[i] = vnodes_prism[i]; }
9704  }
9705  }
9706  }
9707  }
9708 
9709  /*--- Decide whether we need to store this element, i.e., check if
9710  any of the nodes making up this element have a global index value
9711  that falls within the range of our linear partitioning. ---*/
9712 
9713  for (unsigned short i = 0; i < N_POINTS_PRISM; i++) {
9714 
9715  local_index = vnodes_prism[i]-starting_node[rank];
9716 
9717  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9718 
9719  /*--- This node is within our linear partition. Mark this
9720  entire element to be added to our list for this rank, and
9721  add the neighboring nodes to this nodes' adjacency list. ---*/
9722 
9723  ElemIn[element_count] = true;
9724 
9725 #ifdef HAVE_MPI
9726 #ifdef HAVE_PARMETIS
9727  /*--- Build adjacency assuming the VTK connectivity ---*/
9728  if (i < 3) {
9729  adj_nodes[local_index].push_back(vnodes_prism[(i+1)%3]);
9730  adj_nodes[local_index].push_back(vnodes_prism[(i+2)%3]);
9731  } else {
9732  adj_nodes[local_index].push_back(vnodes_prism[(i-2)%3+3]);
9733  adj_nodes[local_index].push_back(vnodes_prism[(i-1)%3+3]);
9734  }
9735  adj_nodes[local_index].push_back(vnodes_prism[(i+3)%6]);
9736 #endif
9737 #endif
9738  }
9739  }
9740 
9741  MI = ElemIn.find(element_count);
9742  if (MI != ElemIn.end()) local_element_count++;
9743 
9744  break;
9745 
9746  case PYRAMID:
9747 
9748  /*--- Load the connectivity for this element. ---*/
9749 
9750  elem_line >> vnodes_pyramid[0];
9751  elem_line >> vnodes_pyramid[1];
9752  elem_line >> vnodes_pyramid[2];
9753  elem_line >> vnodes_pyramid[3];
9754  elem_line >> vnodes_pyramid[4];
9755 
9756  if (actuator_disk) {
9757  for (unsigned short i = 0; i<N_POINTS_PYRAMID; i++) {
9758  if (ActDisk_Bool[vnodes_pyramid[i]]) {
9759 
9760  Xcg = 0.0; Counter = 0;
9761  for (unsigned short j = 0; j<N_POINTS_PYRAMID; j++) {
9762  if (vnodes_pyramid[j] < Global_nPoint-ActDiskNewPoints) {
9763  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_pyramid[j]]];
9764  Counter++;
9765  }
9766  }
9767  Xcg = Xcg / su2double(Counter);
9768 
9769  if (Counter != 0) {
9770  if (Xcg > Xloc) { vnodes_pyramid[i] = ActDiskPoint_Back[vnodes_pyramid[i]]; }
9771  else { vnodes_pyramid[i] = vnodes_pyramid[i]; }
9772  }
9773  }
9774  }
9775  }
9776 
9777  /*--- Decide whether we need to store this element, i.e., check if
9778  any of the nodes making up this element have a global index value
9779  that falls within the range of our linear partitioning. ---*/
9780 
9781  for (unsigned short i = 0; i < N_POINTS_PYRAMID; i++) {
9782 
9783  local_index = vnodes_pyramid[i]-starting_node[rank];
9784 
9785  if ((local_index >= 0) && (local_index < (long)nPoint)) {
9786 
9787  /*--- This node is within our linear partition. Mark this
9788  entire element to be added to our list for this rank, and
9789  add the neighboring nodes to this nodes' adjacency list. ---*/
9790 
9791  ElemIn[element_count] = true;
9792 
9793 #ifdef HAVE_MPI
9794 #ifdef HAVE_PARMETIS
9795  /*--- Build adjacency assuming the VTK connectivity ---*/
9796  if (i < 4) {
9797  adj_nodes[local_index].push_back(vnodes_pyramid[(i+1)%4]);
9798  adj_nodes[local_index].push_back(vnodes_pyramid[(i+3)%4]);
9799  adj_nodes[local_index].push_back(vnodes_pyramid[4]);
9800  } else {
9801  adj_nodes[local_index].push_back(vnodes_pyramid[0]);
9802  adj_nodes[local_index].push_back(vnodes_pyramid[1]);
9803  adj_nodes[local_index].push_back(vnodes_pyramid[2]);
9804  adj_nodes[local_index].push_back(vnodes_pyramid[3]);
9805  }
9806 #endif
9807 #endif
9808  }
9809  }
9810 
9811  MI = ElemIn.find(element_count);
9812  if (MI != ElemIn.end()) local_element_count++;
9813 
9814  break;
9815  }
9816  element_count++;
9817  }
9818  if (element_count == Global_nElem) break;
9819  }
9820  }
9821 
9822  mesh_file.close();
9823 
9824  /*--- Store the number of elements on the whole domain, excluding halos. ---*/
9825 
9826  Global_nElemDomain = element_count;
9827 
9828  /*--- Store the number of local elements on each rank after determining
9829  which elements must be kept in the loop above. ---*/
9830 
9831  nElem = local_element_count;
9832 
9833  /*--- Begin dealing with the partitioning by adjusting the adjacency
9834  information and clear out memory where possible. ---*/
9835 
9836 #ifdef HAVE_MPI
9837 #ifdef HAVE_PARMETIS
9838 
9839  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
9840  cout << "Executing the partitioning functions." << endl;
9841 
9842  /*--- Post process the adjacency information in order to get it into the
9843  proper format before sending the data to ParMETIS. We need to remove
9844  repeats and adjust the size of the array for each local node. ---*/
9845 
9846  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
9847  cout << "Building the graph adjacency structure." << endl;
9848 
9849  unsigned long loc_adjc_size=0;
9850  vector<unsigned long> adjac_vec;
9851  unsigned long adj_elem_size;
9852 
9853  xadj = new idx_t [npoint_procs[rank]+1];
9854  xadj[0]=0;
9855  vector<unsigned long> temp_adjacency;
9856  unsigned long local_count=0;
9857 
9858  /*--- Here, we transfer the adjacency information from a multi-dim vector
9859  on a node-by-node basis into a single vector container. First, we sort
9860  the entries and remove the duplicates we find for each node, then we
9861  copy it into the single vect and clear memory from the multi-dim vec. ---*/
9862 
9863  for (unsigned long i = 0; i < nPoint; i++) {
9864 
9865  for (j = 0; j<adj_nodes[i].size(); j++) {
9866  temp_adjacency.push_back(adj_nodes[i][j]);
9867  }
9868 
9869  sort(temp_adjacency.begin(), temp_adjacency.end());
9870  it = unique(temp_adjacency.begin(), temp_adjacency.end());
9871  loc_adjc_size = it - temp_adjacency.begin();
9872 
9873  temp_adjacency.resize(loc_adjc_size);
9874  xadj[local_count+1]=xadj[local_count]+loc_adjc_size;
9875  local_count++;
9876 
9877  for (j = 0; j<loc_adjc_size; j++) {
9878  adjac_vec.push_back(temp_adjacency[j]);
9879  }
9880 
9881  temp_adjacency.clear();
9882  adj_nodes[i].clear();
9883 
9884  }
9885 
9886  /*--- Now that we know the size, create the final adjacency array. This
9887  is the array that we will feed to ParMETIS for partitioning. ---*/
9888 
9889  adj_elem_size = xadj[npoint_procs[rank]];
9890  adjacency = new idx_t [adj_elem_size];
9891  copy(adjac_vec.begin(), adjac_vec.end(), adjacency);
9892 
9894  adjacency_size = adj_elem_size;
9895 
9896  /*--- Free temporary memory used to build the adjacency. ---*/
9897 
9898  adjac_vec.clear();
9899  adj_nodes.clear();
9900 
9901 #endif
9902 #endif
9903 
9904  /*--- Open the mesh file again and now that we know the number of
9905  elements needed on each partition, allocate memory for them. ---*/
9906 
9907  mesh_file.open(cstr, ios::in);
9908 
9909  /*--- If more than one, find the zone in the mesh file ---*/
9910 
9911  if (val_nZone > 1) {
9912  while (getline (mesh_file,text_line)) {
9913  /*--- Search for the current domain ---*/
9914  position = text_line.find ("IZONE=",0);
9915  if (position != string::npos) {
9916  text_line.erase (0,6);
9917  unsigned short jDomain = atoi(text_line.c_str());
9918  if (jDomain == val_iZone+1) {
9919  break;
9920  }
9921  }
9922  }
9923  }
9924 
9925  while (getline (mesh_file, text_line)) {
9926 
9927  /*--- Read the information about inner elements ---*/
9928 
9929  position = text_line.find ("NELEM=",0);
9930  if (position != string::npos) {
9931 
9932  /*--- Allocate space for elements ---*/
9933  elem = new CPrimalGrid*[nElem];
9934 
9935  /*--- Set up the global to local element mapping. ---*/
9936  Global_to_Local_Elem.clear();
9937 
9938  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
9939  cout << "Distributing elements across all ranks." << endl;
9940 
9941  /*--- Loop over all the volumetric elements and store any element that
9942  contains at least one of an owned node for this rank (i.e., there will
9943  be element redundancy, since multiple ranks will store the same elems
9944  on the boundaries of the initial linear partitioning. ---*/
9945 
9946  element_count = 0; local_element_count = 0;
9947  while (element_count < Global_nElem) {
9948  getline(mesh_file, text_line);
9949  istringstream elem_line(text_line);
9950 
9951  /*--- If this element was marked as required, check type and store. ---*/
9952 
9953  map<unsigned long, bool>::const_iterator MI = ElemIn.find(element_count);
9954  if (MI != ElemIn.end()) {
9955 
9956  elem_line >> VTK_Type;
9957  switch(VTK_Type) {
9958 
9959  case TRIANGLE:
9960 
9961  /*--- Load the connectivity for this element. ---*/
9962 
9963  elem_line >> vnodes_triangle[0];
9964  elem_line >> vnodes_triangle[1];
9965  elem_line >> vnodes_triangle[2];
9966 
9967  if (actuator_disk) {
9968  for (unsigned short i = 0; i<N_POINTS_TRIANGLE; i++) {
9969  if (ActDisk_Bool[vnodes_triangle[i]]) {
9970 
9971  Xcg = 0.0; Counter = 0;
9972  for (unsigned short j = 0; j<N_POINTS_TRIANGLE; j++) {
9973  if (vnodes_triangle[j] < Global_nPoint-ActDiskNewPoints) {
9974  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_triangle[j]]];
9975  Counter++;
9976  }
9977  }
9978  Xcg = Xcg / su2double(Counter);
9979 
9980  if (Counter != 0) {
9981  if (Xcg > Xloc) {
9982  vnodes_triangle[i] = ActDiskPoint_Back[vnodes_triangle[i]];
9983  }
9984  else { vnodes_triangle[i] = vnodes_triangle[i]; }
9985  }
9986 
9987  }
9988  }
9989  }
9990 
9991  /*--- If any of the nodes were within the linear partition, the
9992  element is added to our element data structure. ---*/
9993 
9994  Global_to_Local_Elem[element_count] = local_element_count;
9995  elem[local_element_count] = new CTriangle(vnodes_triangle[0],
9996  vnodes_triangle[1],
9997  vnodes_triangle[2], 2);
9998  local_element_count++;
9999  nelem_triangle++;
10000  break;
10001 
10002  case QUADRILATERAL:
10003 
10004  /*--- Load the connectivity for this element. ---*/
10005 
10006  elem_line >> vnodes_quad[0];
10007  elem_line >> vnodes_quad[1];
10008  elem_line >> vnodes_quad[2];
10009  elem_line >> vnodes_quad[3];
10010 
10011  if (actuator_disk) {
10012  for (unsigned short i = 0; i<N_POINTS_QUADRILATERAL; i++) {
10013  if (ActDisk_Bool[vnodes_quad[i]]) {
10014 
10015  Xcg = 0.0; Counter = 0;
10016  for (unsigned short j = 0; j<N_POINTS_QUADRILATERAL; j++) {
10017  if (vnodes_quad[j] < Global_nPoint-ActDiskNewPoints) {
10018  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_quad[j]]];
10019  Counter++;
10020  }
10021  }
10022  Xcg = Xcg / su2double(Counter);
10023 
10024 
10025  if (Counter != 0) {
10026  if (Xcg > Xloc) {
10027  vnodes_quad[i] = ActDiskPoint_Back[vnodes_quad[i]];
10028  }
10029  else { vnodes_quad[i] = vnodes_quad[i]; }
10030  }
10031 
10032  }
10033  }
10034  }
10035 
10036  /*--- If any of the nodes were within the linear partition, the
10037  element is added to our element data structure. ---*/
10038 
10039  Global_to_Local_Elem[element_count] = local_element_count;
10040  elem[local_element_count] = new CQuadrilateral(vnodes_quad[0],
10041  vnodes_quad[1],
10042  vnodes_quad[2],
10043  vnodes_quad[3], 2);
10044  local_element_count++;
10045  nelem_quad++;
10046  break;
10047 
10048  case TETRAHEDRON:
10049 
10050  /*--- Load the connectivity for this element. ---*/
10051 
10052  elem_line >> vnodes_tetra[0];
10053  elem_line >> vnodes_tetra[1];
10054  elem_line >> vnodes_tetra[2];
10055  elem_line >> vnodes_tetra[3];
10056 
10057  if (actuator_disk) {
10058  for (unsigned short i = 0; i<N_POINTS_TETRAHEDRON; i++) {
10059  if (ActDisk_Bool[vnodes_tetra[i]]) {
10060 
10061  Xcg = 0.0; Counter = 0;
10062  for (unsigned short j = 0; j<N_POINTS_TETRAHEDRON; j++) {
10063  if (vnodes_tetra[j] < Global_nPoint-ActDiskNewPoints) {
10064  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_tetra[j]]];
10065  Counter++;
10066  }
10067  }
10068  Xcg = Xcg / su2double(Counter);
10069 
10070 
10071  if (Counter != 0) {
10072  if (Xcg > Xloc) {
10073  vnodes_tetra[i] = ActDiskPoint_Back[vnodes_tetra[i]];
10074  }
10075  else { vnodes_tetra[i] = vnodes_tetra[i]; }
10076  }
10077 
10078  }
10079  }
10080  }
10081 
10082  /*--- If any of the nodes were within the linear partition, the
10083  element is added to our element data structure. ---*/
10084 
10085  Global_to_Local_Elem[element_count] = local_element_count;
10086  elem[local_element_count] = new CTetrahedron(vnodes_tetra[0],
10087  vnodes_tetra[1],
10088  vnodes_tetra[2],
10089  vnodes_tetra[3]);
10090  local_element_count++;
10091  nelem_tetra++;
10092  break;
10093 
10094  case HEXAHEDRON:
10095 
10096  /*--- Load the connectivity for this element. ---*/
10097 
10098  elem_line >> vnodes_hexa[0];
10099  elem_line >> vnodes_hexa[1];
10100  elem_line >> vnodes_hexa[2];
10101  elem_line >> vnodes_hexa[3];
10102  elem_line >> vnodes_hexa[4];
10103  elem_line >> vnodes_hexa[5];
10104  elem_line >> vnodes_hexa[6];
10105  elem_line >> vnodes_hexa[7];
10106 
10107  if (actuator_disk) {
10108  for (unsigned short i = 0; i<N_POINTS_HEXAHEDRON; i++) {
10109  if (ActDisk_Bool[vnodes_hexa[i]]) {
10110 
10111  Xcg = 0.0; Counter = 0;
10112  for (unsigned short j = 0; j<N_POINTS_HEXAHEDRON; j++) {
10113  if (vnodes_hexa[j] < Global_nPoint-ActDiskNewPoints) {
10114  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_hexa[j]]];
10115  Counter++;
10116  }
10117  }
10118  Xcg = Xcg / su2double(Counter);
10119 
10120  if (Counter != 0) {
10121  if (Xcg > Xloc) { vnodes_hexa[i] = ActDiskPoint_Back[vnodes_hexa[i]]; }
10122  else { vnodes_hexa[i] = vnodes_hexa[i]; }
10123  }
10124  }
10125  }
10126  }
10127 
10128  /*--- If any of the nodes were within the linear partition, the
10129  element is added to our element data structure. ---*/
10130 
10131  Global_to_Local_Elem[element_count] = local_element_count;
10132  elem[local_element_count] = new CHexahedron(vnodes_hexa[0],
10133  vnodes_hexa[1],
10134  vnodes_hexa[2],
10135  vnodes_hexa[3],
10136  vnodes_hexa[4],
10137  vnodes_hexa[5],
10138  vnodes_hexa[6],
10139  vnodes_hexa[7]);
10140  local_element_count++;
10141  nelem_hexa++;
10142  break;
10143 
10144  case PRISM:
10145 
10146  /*--- Load the connectivity for this element. ---*/
10147 
10148  elem_line >> vnodes_prism[0];
10149  elem_line >> vnodes_prism[1];
10150  elem_line >> vnodes_prism[2];
10151  elem_line >> vnodes_prism[3];
10152  elem_line >> vnodes_prism[4];
10153  elem_line >> vnodes_prism[5];
10154 
10155  if (actuator_disk) {
10156  for (unsigned short i = 0; i<N_POINTS_PRISM; i++) {
10157  if (ActDisk_Bool[vnodes_prism[i]]) {
10158 
10159  Xcg = 0.0; Counter = 0;
10160  for (unsigned short j = 0; j<N_POINTS_PRISM; j++) {
10161  if (vnodes_prism[j] < Global_nPoint-ActDiskNewPoints) {
10162  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_prism[j]]];
10163  Counter++;
10164  }
10165  }
10166  Xcg = Xcg / su2double(Counter);
10167 
10168  if (Counter != 0) {
10169  if (Xcg > Xloc) { vnodes_prism[i] = ActDiskPoint_Back[vnodes_prism[i]]; }
10170  else { vnodes_prism[i] = vnodes_prism[i]; }
10171  }
10172  }
10173  }
10174  }
10175 
10176  /*--- If any of the nodes were within the linear partition, the
10177  element is added to our element data structure. ---*/
10178 
10179  Global_to_Local_Elem[element_count] = local_element_count;
10180  elem[local_element_count] = new CPrism(vnodes_prism[0],
10181  vnodes_prism[1],
10182  vnodes_prism[2],
10183  vnodes_prism[3],
10184  vnodes_prism[4],
10185  vnodes_prism[5]);
10186  local_element_count++;
10187  nelem_prism++;
10188  break;
10189 
10190  case PYRAMID:
10191 
10192  /*--- Load the connectivity for this element. ---*/
10193 
10194  elem_line >> vnodes_pyramid[0];
10195  elem_line >> vnodes_pyramid[1];
10196  elem_line >> vnodes_pyramid[2];
10197  elem_line >> vnodes_pyramid[3];
10198  elem_line >> vnodes_pyramid[4];
10199 
10200  if (actuator_disk) {
10201  for (unsigned short i = 0; i<N_POINTS_PYRAMID; i++) {
10202  if (ActDisk_Bool[vnodes_pyramid[i]]) {
10203 
10204  Xcg = 0.0; Counter = 0;
10205  for (unsigned short j = 0; j<N_POINTS_PYRAMID; j++) {
10206  if (vnodes_pyramid[j] < Global_nPoint-ActDiskNewPoints) {
10207  Xcg += CoordXVolumePoint[VolumePoint_Inv[vnodes_pyramid[j]]];
10208  Counter++;
10209  }
10210  }
10211  Xcg = Xcg / su2double(Counter);
10212 
10213  if (Counter != 0) {
10214  if (Xcg > Xloc) { vnodes_pyramid[i] = ActDiskPoint_Back[vnodes_pyramid[i]]; }
10215  else { vnodes_pyramid[i] = vnodes_pyramid[i]; }
10216  }
10217  }
10218  }
10219  }
10220 
10221  /*--- If any of the nodes were within the linear partition, the
10222  element is added to our element data structure. ---*/
10223 
10224  Global_to_Local_Elem[element_count]=local_element_count;
10225  elem[local_element_count] = new CPyramid(vnodes_pyramid[0],
10226  vnodes_pyramid[1],
10227  vnodes_pyramid[2],
10228  vnodes_pyramid[3],
10229  vnodes_pyramid[4]);
10230  local_element_count++;
10231  nelem_pyramid++;
10232  break;
10233 
10234  }
10235  }
10236  element_count++;
10237  }
10238  if (element_count == Global_nElem) break;
10239  }
10240  }
10241 
10242  mesh_file.close();
10243 
10244  /*--- For now, the boundary marker information is still read by the
10245  master node alone (and eventually distributed by the master as well).
10246  In the future, this component will also be performed in parallel. ---*/
10247 
10248  mesh_file.open(cstr, ios::in);
10249 
10250  /*--- If more than one, find the zone in the mesh file ---*/
10251 
10252 
10253  if (val_nZone > 1) {
10254  while (getline (mesh_file,text_line)) {
10255  /*--- Search for the current domain ---*/
10256  position = text_line.find ("IZONE=",0);
10257  if (position != string::npos) {
10258  text_line.erase (0,6);
10259  unsigned short jDomain = atoi(text_line.c_str());
10260  if (jDomain == val_iZone+1) {
10261  break;
10262  }
10263  }
10264  }
10265  }
10266 
10267  while (getline (mesh_file, text_line)) {
10268 
10269  /*--- Read number of markers ---*/
10270 
10271  position = text_line.find ("NMARK=",0);
10272  boundary_marker_count = 0;
10273 
10274  if (position != string::npos) {
10275  text_line.erase (0,6); nMarker = atoi(text_line.c_str());
10276 
10277  if (actuator_disk) { nMarker++; }
10278 
10279  if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl;
10280  config->SetnMarker_All(nMarker);
10281  bound = new CPrimalGrid**[nMarker];
10282  nElem_Bound = new unsigned long [nMarker];
10283  Tag_to_Marker = new string [nMarker_Max];
10284 
10285  bool duplicate = false;
10286  iMarker=0;
10287  do {
10288 
10289  getline (mesh_file, text_line);
10290  text_line.erase (0,11);
10291  string::size_type position;
10292 
10293  for (iChar = 0; iChar < 20; iChar++) {
10294  position = text_line.find( " ", 0 );
10295  if (position != string::npos) text_line.erase (position,1);
10296  position = text_line.find( "\r", 0 );
10297  if (position != string::npos) text_line.erase (position,1);
10298  position = text_line.find( "\n", 0 );
10299  if (position != string::npos) text_line.erase (position,1);
10300  }
10301  Marker_Tag = text_line.c_str();
10302 
10303  duplicate = false;
10304  if ((actuator_disk) && ( Marker_Tag == config->GetMarker_ActDiskInlet_TagBound(0))) {
10305  duplicate = true;
10306  Marker_Tag_Duplicate = config->GetMarker_ActDiskOutlet_TagBound(0);
10307  }
10308 
10309  /*--- Physical boundaries definition ---*/
10310 
10311  if (Marker_Tag != "SEND_RECEIVE") {
10312  getline (mesh_file, text_line);
10313  text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str());
10314  if (duplicate) nElem_Bound[iMarker+1] = nElem_Bound[iMarker];
10315 
10316  if (rank == MASTER_NODE) {
10317  cout << nElem_Bound[iMarker] << " boundary elements in index "<< iMarker <<" (Marker = " <<Marker_Tag<< ")." << endl;
10318  if (duplicate) cout << nElem_Bound[iMarker+1] << " boundary elements in index "<< iMarker+1 <<" (Marker = " <<Marker_Tag_Duplicate<< ")." << endl;
10319  }
10320 
10321  /*--- Allocate space for elements ---*/
10322 
10323  bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]];
10324 
10325  if (duplicate) bound[iMarker+1] = new CPrimalGrid* [nElem_Bound[iMarker+1]];
10326 
10327  nelem_edge_bound = 0; nelem_triangle_bound = 0; nelem_quad_bound = 0; ielem = 0;
10328  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
10329  getline(mesh_file, text_line);
10330  istringstream bound_line(text_line);
10331  bound_line >> VTK_Type;
10332  switch(VTK_Type) {
10333  case LINE:
10334 
10335  if (nDim == 3) {
10336  SU2_MPI::Error("Please remove line boundary conditions from the mesh file!", CURRENT_FUNCTION);
10337  }
10338 
10339  bound_line >> vnodes_edge[0]; bound_line >> vnodes_edge[1];
10340  bound[iMarker][ielem] = new CLine(vnodes_edge[0], vnodes_edge[1],2);
10341 
10342  if (duplicate) {
10343  if (ActDisk_Bool[vnodes_edge[0]]) { vnodes_edge[0] = ActDiskPoint_Back[vnodes_edge[0]]; }
10344  if (ActDisk_Bool[vnodes_edge[1]]) { vnodes_edge[1] = ActDiskPoint_Back[vnodes_edge[1]]; }
10345  bound[iMarker+1][ielem] = new CLine(vnodes_edge[0], vnodes_edge[1],2);
10346  }
10347 
10348  ielem++; nelem_edge_bound++; break;
10349 
10350  case TRIANGLE:
10351  bound_line >> vnodes_triangle[0]; bound_line >> vnodes_triangle[1]; bound_line >> vnodes_triangle[2];
10352  bound[iMarker][ielem] = new CTriangle(vnodes_triangle[0], vnodes_triangle[1], vnodes_triangle[2],3);
10353 
10354  if (duplicate) {
10355  if (ActDisk_Bool[vnodes_triangle[0]]) { vnodes_triangle[0] = ActDiskPoint_Back[vnodes_triangle[0]]; }
10356  if (ActDisk_Bool[vnodes_triangle[1]]) { vnodes_triangle[1] = ActDiskPoint_Back[vnodes_triangle[1]]; }
10357  if (ActDisk_Bool[vnodes_triangle[2]]) { vnodes_triangle[2] = ActDiskPoint_Back[vnodes_triangle[2]]; }
10358  bound[iMarker+1][ielem] = new CTriangle(vnodes_triangle[0], vnodes_triangle[1], vnodes_triangle[2],3);
10359 
10360  }
10361 
10362  ielem++; nelem_triangle_bound++; break;
10363 
10364  case QUADRILATERAL:
10365 
10366  bound_line >> vnodes_quad[0]; bound_line >> vnodes_quad[1]; bound_line >> vnodes_quad[2]; bound_line >> vnodes_quad[3];
10367 
10368  bound[iMarker][ielem] = new CQuadrilateral(vnodes_quad[0], vnodes_quad[1], vnodes_quad[2], vnodes_quad[3],3);
10369 
10370  if (duplicate) {
10371  if (ActDisk_Bool[vnodes_quad[0]]) { vnodes_quad[0] = ActDiskPoint_Back[vnodes_quad[0]]; }
10372  if (ActDisk_Bool[vnodes_quad[1]]) { vnodes_quad[1] = ActDiskPoint_Back[vnodes_quad[1]]; }
10373  if (ActDisk_Bool[vnodes_quad[2]]) { vnodes_quad[2] = ActDiskPoint_Back[vnodes_quad[2]]; }
10374  if (ActDisk_Bool[vnodes_quad[3]]) { vnodes_quad[3] = ActDiskPoint_Back[vnodes_quad[3]]; }
10375  bound[iMarker+1][ielem] = new CQuadrilateral(vnodes_quad[0], vnodes_quad[1], vnodes_quad[2], vnodes_quad[3],3);
10376  }
10377 
10378  ielem++; nelem_quad_bound++;
10379 
10380  break;
10381 
10382 
10383  }
10384  }
10385 
10386  /*--- Update config information storing the boundary information in the right place ---*/
10387 
10388  Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag;
10389  config->SetMarker_All_TagBound(iMarker, Marker_Tag);
10390  config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag));
10391  config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag));
10392  config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag));
10393  config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag));
10394  config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag));
10395  config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag));
10396  config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag));
10397  config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag));
10398  config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag));
10399  config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag));
10400  config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag));
10401  config->SetMarker_All_SendRecv(iMarker, NONE);
10402  config->SetMarker_All_Turbomachinery(iMarker, config->GetMarker_CfgFile_Turbomachinery(Marker_Tag));
10403  config->SetMarker_All_TurbomachineryFlag(iMarker, config->GetMarker_CfgFile_TurbomachineryFlag(Marker_Tag));
10404  config->SetMarker_All_MixingPlaneInterface(iMarker, config->GetMarker_CfgFile_MixingPlaneInterface(Marker_Tag));
10405 
10406  if (duplicate) {
10407  Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag_Duplicate)] = Marker_Tag_Duplicate;
10408  config->SetMarker_All_TagBound(iMarker+1, Marker_Tag_Duplicate);
10409  config->SetMarker_All_KindBC(iMarker+1, config->GetMarker_CfgFile_KindBC(Marker_Tag_Duplicate));
10410  config->SetMarker_All_Monitoring(iMarker+1, config->GetMarker_CfgFile_Monitoring(Marker_Tag_Duplicate));
10411  config->SetMarker_All_GeoEval(iMarker+1, config->GetMarker_CfgFile_GeoEval(Marker_Tag_Duplicate));
10412  config->SetMarker_All_Designing(iMarker+1, config->GetMarker_CfgFile_Designing(Marker_Tag_Duplicate));
10413  config->SetMarker_All_Plotting(iMarker+1, config->GetMarker_CfgFile_Plotting(Marker_Tag_Duplicate));
10414  config->SetMarker_All_Analyze(iMarker+1, config->GetMarker_CfgFile_Analyze(Marker_Tag_Duplicate));
10415  config->SetMarker_All_ZoneInterface(iMarker+1, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag_Duplicate));
10416  config->SetMarker_All_DV(iMarker+1, config->GetMarker_CfgFile_DV(Marker_Tag_Duplicate));
10417  config->SetMarker_All_Moving(iMarker+1, config->GetMarker_CfgFile_Moving(Marker_Tag_Duplicate));
10418  config->SetMarker_All_PyCustom(iMarker+1, config->GetMarker_CfgFile_PyCustom(Marker_Tag_Duplicate));
10419  config->SetMarker_All_PerBound(iMarker+1, config->GetMarker_CfgFile_PerBound(Marker_Tag_Duplicate));
10420  config->SetMarker_All_SendRecv(iMarker+1, NONE);
10421 
10422  boundary_marker_count++;
10423  iMarker++;
10424 
10425  }
10426 
10427  }
10428 
10429  /*--- Send-Receive boundaries definition ---*/
10430 
10431  else {
10432 
10433  unsigned long nelem_vertex = 0, vnodes_vertex;
10434  unsigned short transform;
10435  getline (mesh_file, text_line);
10436  text_line.erase (0,13); nElem_Bound[iMarker] = atoi(text_line.c_str());
10437  bound[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]];
10438 
10439  nelem_vertex = 0; ielem = 0;
10440  getline (mesh_file, text_line); text_line.erase (0,8);
10441  config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE);
10442  config->SetMarker_All_SendRecv(iMarker, atoi(text_line.c_str()));
10443 
10444  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
10445  getline(mesh_file, text_line);
10446  istringstream bound_line(text_line);
10447  bound_line >> VTK_Type; bound_line >> vnodes_vertex; bound_line >> transform;
10448 
10449  bound[iMarker][ielem] = new CVertexMPI(vnodes_vertex, nDim);
10450  bound[iMarker][ielem]->SetRotation_Type(transform);
10451  ielem++; nelem_vertex++;
10452  }
10453 
10454  }
10455 
10456  boundary_marker_count++;
10457  iMarker++;
10458 
10459  } while (iMarker < nMarker);
10460 
10461  if (boundary_marker_count == nMarker) break;
10462 
10463  }
10464  }
10465 
10466  while (getline (mesh_file, text_line) && (found_transform == false)) {
10467 
10468  /*--- Read periodic transformation info (center, rotation, translation) ---*/
10469 
10470  position = text_line.find ("NPERIODIC=",0);
10471  if (position != string::npos) {
10472  unsigned short nPeriodic, iPeriodic, iIndex;
10473 
10474  /*--- Set bool signifying that periodic transormations were found ---*/
10475  found_transform = true;
10476 
10477  /*--- Read and store the number of transformations. ---*/
10478  text_line.erase (0,10); nPeriodic = atoi(text_line.c_str());
10479  if (rank == MASTER_NODE) {
10480  if (nPeriodic - 1 != 0)
10481  cout << nPeriodic - 1 << " periodic transformations." << endl;
10482  }
10483  config->SetnPeriodicIndex(nPeriodic);
10484 
10485  /*--- Store center, rotation, & translation in that order for each. ---*/
10486  for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) {
10487  getline (mesh_file, text_line);
10488  position = text_line.find ("PERIODIC_INDEX=",0);
10489  if (position != string::npos) {
10490  text_line.erase (0,15); iIndex = atoi(text_line.c_str());
10491  if (iIndex != iPeriodic) {
10492  SU2_MPI::Error("PERIODIC_INDEX out of order in SU2 file!!", CURRENT_FUNCTION);
10493  }
10494  }
10495  su2double* center = new su2double[3];
10496  su2double* rotation = new su2double[3];
10497  su2double* translate = new su2double[3];
10498  getline (mesh_file, text_line);
10499  istringstream cent(text_line);
10500  cent >> center[0]; cent >> center[1]; cent >> center[2];
10501  config->SetPeriodicCenter(iPeriodic, center);
10502  getline (mesh_file, text_line);
10503  istringstream rot(text_line);
10504  rot >> rotation[0]; rot >> rotation[1]; rot >> rotation[2];
10505  config->SetPeriodicRotation(iPeriodic, rotation);
10506  getline (mesh_file, text_line);
10507  istringstream tran(text_line);
10508  tran >> translate[0]; tran >> translate[1]; tran >> translate[2];
10509  config->SetPeriodicTranslate(iPeriodic, translate);
10510 
10511  delete [] center; delete [] rotation; delete [] translate;
10512  }
10513  }
10514  }
10515 
10516  /*--- If no periodic transormations were found, store default zeros ---*/
10517 
10518  if (!found_transform) {
10519  unsigned short nPeriodic = 1, iPeriodic = 0;
10520  config->SetnPeriodicIndex(nPeriodic);
10521  su2double* center = new su2double[3];
10522  su2double* rotation = new su2double[3];
10523  su2double* translate = new su2double[3];
10524  for (unsigned short iDim = 0; iDim < 3; iDim++) {
10525  center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0;
10526  }
10527  config->SetPeriodicCenter(iPeriodic, center);
10528  config->SetPeriodicRotation(iPeriodic, rotation);
10529  config->SetPeriodicTranslate(iPeriodic, translate);
10530  delete [] center; delete [] rotation; delete [] translate;
10531  }
10532 
10533  /*--- Close the input file ---*/
10534 
10535  mesh_file.close();
10536 
10537  /*--- Release actuator disk memory ---*/
10538 
10539  if (actuator_disk) {
10540  delete [] ActDisk_Bool;
10541  delete [] ActDiskPoint_Back;
10542  delete [] VolumePoint_Inv;
10543  delete [] CoordXVolumePoint;
10544  delete [] CoordYVolumePoint;
10545  delete [] CoordZVolumePoint;
10546  delete [] CoordXActDisk;
10547  delete [] CoordYActDisk;
10548  delete [] CoordZActDisk;
10549  }
10550 
10551 }
10552 
10553 void CPhysicalGeometry::Read_CGNS_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) {
10554 
10555  /*--- Original CGNS reader implementation by Thomas D. Economon,
10556  Francisco Palacios. Improvements for mixed-element meshes generated
10557  by ICEM added by Martin Spel (3D) & Shlomy Shitrit (2D), April 2014.
10558  Parallel version by Thomas D. Economon, February 2015. ---*/
10559 
10560 #ifdef HAVE_CGNS
10561 
10562  string text_line, Marker_Tag;
10563  ifstream mesh_file;
10564  unsigned short VTK_Type = 0, iMarker = 0;
10565  unsigned short nMarker_Max = config->GetnMarker_Max();
10566  unsigned long iPoint = 0, iProcessor = 0, ielem = 0, GlobalIndex = 0;
10567  unsigned long globalOffset = 0;
10568  nZone = val_nZone;
10569 
10570  /*--- Local variables needed when calling the CGNS mid-level API. ---*/
10571 
10572  unsigned long vnodes_cgns[8] = {0,0,0,0,0,0,0,0};
10573  su2double Coord_cgns[3] = {0.0,0.0,0.0};
10574  int fn, nbases = 0, nzones = 0, ngrids = 0, ncoords = 0, nsections = 0;
10575  int *vertices = NULL, *cells = NULL, nMarkers = 0, *boundVerts = NULL, npe;
10576  int interiorElems = 0, totalVerts = 0;
10577  int cell_dim = 0, phys_dim = 0, nbndry, parent_flag, file_type;
10578  char basename[CGNS_STRING_SIZE], zonename[CGNS_STRING_SIZE];
10579  char coordname[CGNS_STRING_SIZE];
10580  cgsize_t* cgsize; cgsize = new cgsize_t[3];
10581  ZoneType_t zonetype;
10582  DataType_t datatype;
10583  passivedouble** coordArray = NULL;
10584  passivedouble*** gridCoords = NULL;
10585  ElementType_t elemType;
10586  cgsize_t range_min, range_max, startE, endE;
10587  range_min = 1;
10588  string currentElem;
10589  int** elemTypeVTK = NULL;
10590  int** elemIndex = NULL;
10591  int** elemBegin = NULL;
10592  int** elemEnd = NULL;
10593  int** nElems = NULL;
10594  cgsize_t**** connElems = NULL;
10595  cgsize_t* connElemCGNS = NULL;
10596  cgsize_t* connElemTemp = NULL;
10597  cgsize_t ElementDataSize = 0;
10598  cgsize_t* parentData = NULL;
10599  int** dataSize = NULL;
10600  bool** isInternal = NULL;
10601  char*** sectionNames = NULL;
10602 
10603  /*--- Initialize counters for local/global points & elements ---*/
10604 
10605 #ifdef HAVE_MPI
10606  unsigned long Local_nElem;
10607  unsigned long Local_nElemTri, Local_nElemQuad, Local_nElemTet;
10608  unsigned long Local_nElemHex, Local_nElemPrism, Local_nElemPyramid;
10609  SU2_MPI::Request *send_req, *recv_req;
10610  SU2_MPI::Status status;
10611  int ind;
10612 #endif
10613 
10614  /*--- Initialize counters for local/global points & elements ---*/
10615 
10617  nelem_edge = 0; Global_nelem_edge = 0;
10619  nelem_quad = 0; Global_nelem_quad = 0;
10621  nelem_hexa = 0; Global_nelem_hexa = 0;
10624 
10625  /*--- Initialize some additional counters for the parallel partitioning ---*/
10626 
10627  unsigned long total_pt_accounted = 0;
10628  unsigned long rem_points = 0;
10629  unsigned long element_count = 0;
10630  unsigned long element_remainder = 0;
10631  unsigned long total_elems = 0;
10632 
10633  /*--- Allocate memory for the linear partitioning of the mesh. These
10634  arrays are the size of the number of ranks. ---*/
10635 
10636  starting_node = new unsigned long[size];
10637  ending_node = new unsigned long[size];
10638  npoint_procs = new unsigned long[size];
10639  nPoint_Linear = new unsigned long[size+1];
10640 
10641  unsigned long *nElem_Linear = new unsigned long[size];
10642 
10643  unsigned long *elemB = new unsigned long[size];
10644  unsigned long *elemE = new unsigned long[size];
10645 
10646  unsigned long *elemGlobalID = NULL;
10647 
10648  unsigned short *nPoinPerElem = NULL;
10649  unsigned short *elemTypes = NULL;
10650 
10651  bool *isMixed = NULL;
10652 
10653  unsigned short connSize = 10;
10654 
10655  /*--- Check whether the supplied file is truly a CGNS file. ---*/
10656  if (cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK) {
10657  SU2_MPI::Error(val_mesh_filename + string(" was not found or is not a CGNS file."), CURRENT_FUNCTION);
10658  }
10659 
10660  /*--- Open the CGNS file for reading. The value of fn returned
10661  is the specific index number for this file and will be
10662  repeatedly used in the function calls. ---*/
10663 
10664  if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn)) cg_error_exit();
10665  if (rank == MASTER_NODE) {
10666  cout << "Reading the CGNS file: ";
10667  cout << val_mesh_filename.c_str() << "." << endl;
10668  }
10669 
10670  /*--- Get the number of databases. This is the highest node
10671  in the CGNS heirarchy. ---*/
10672 
10673  if ( cg_nbases(fn, &nbases) ) cg_error_exit();
10674  if (rank == MASTER_NODE)
10675  cout << "CGNS file contains " << nbases << " database(s)." << endl;
10676 
10677  /*--- Check if there is more than one database. Throw an
10678  error if there is because this reader can currently
10679  only handle one database. ---*/
10680 
10681  if ( nbases > 1 ) {
10682  SU2_MPI::Error("CGNS reader currently incapable of handling more than 1 database.", CURRENT_FUNCTION);
10683  }
10684 
10685  /*--- Read the databases. Note that the CGNS indexing starts at 1. ---*/
10686 
10687  for (int i = 1; i <= nbases; i++) {
10688 
10689  if (cg_base_read(fn, i, basename, &cell_dim, &phys_dim)) cg_error_exit();
10690 
10691  /*--- Get the number of zones for this base. ---*/
10692 
10693  if ( cg_nzones(fn, i, &nzones) ) cg_error_exit();
10694  if (rank == MASTER_NODE) {
10695  cout << "Database " << i << ", " << basename << ": " << nzones;
10696  cout << " zone(s), cell dimension of " << cell_dim << ", physical ";
10697  cout << "dimension of " << phys_dim << "." << endl;
10698  }
10699 
10700  /*--- Check if there is more than one zone. Throw an
10701  error if there is, because this reader can currently
10702  only handle one zone. This could be extended in the future. ---*/
10703 
10704  if ( nzones > 1 ) {
10705  SU2_MPI::Error("CGNS reader currently incapable of handling more than 1 zone.", CURRENT_FUNCTION);
10706  }
10707 
10708  /*--- Initialize some data structures for all zones. ---*/
10709 
10710  vertices = new int[nzones];
10711  cells = new int[nzones];
10712  boundVerts = new int[nzones];
10713  coordArray = new passivedouble*[nzones];
10714  gridCoords = new passivedouble**[nzones];
10715  elemTypeVTK = new int*[nzones];
10716  elemIndex = new int*[nzones];
10717  elemBegin = new int*[nzones];
10718  elemEnd = new int*[nzones];
10719  nElems = new int*[nzones];
10720  dataSize = new int*[nzones];
10721  isInternal = new bool*[nzones];
10722  nMarkers = 0;
10723  sectionNames = new char**[nzones];
10724  connElems = new cgsize_t***[nzones];
10725 
10726  /*--- Loop over all zones in this base. Again, indexing starts at 1. ---*/
10727 
10728  for (int j = 1; j <= nzones; j++) {
10729 
10730  connElems[j-1] = NULL;
10731 
10732  /*--- Read the basic information for this zone, including
10733  the name and the number of vertices, cells, and
10734  boundary cells which are stored in the cgsize variable. ---*/
10735 
10736  if (cg_zone_read(fn, i, j, zonename, cgsize)) cg_error_exit();
10737 
10738  /*--- Rename the zone size information for clarity.
10739  NOTE: The number of cells here may be only the number of
10740  interior elements or it may be the total. This needs to
10741  be counted explicitly later. ---*/
10742 
10743  vertices[j-1] = cgsize[0];
10744  cells[j-1] = cgsize[1];
10745  boundVerts[j-1] = cgsize[2];
10746 
10747  /*--- Increment the total number of vertices from all zones. ---*/
10748 
10749  nPoint = vertices[j-1];
10750  nPointDomain = vertices[j-1];
10751 
10752  Global_nPoint = vertices[j-1];
10753  Global_nPointDomain = vertices[j-1];
10754 
10755  totalVerts += vertices[j-1];
10756 
10757  /*--- Print some information about the current zone. ---*/
10758 
10759  if (cg_zone_type(fn, i, j, &zonetype)) cg_error_exit();
10760  if (rank == MASTER_NODE) {
10761  cout << "Zone " << j << ", " << zonename << ": " << vertices[j-1];
10762  cout << " vertices, " << cells[j-1] << " cells, " << boundVerts[j-1];
10763  cout << " boundary vertices." << endl;
10764  }
10765 
10766  /*--- Retrieve the number of grids in this zone. For now, we know
10767  this is one, but to be more general, this will need to check and
10768  allow for a loop over all grids. ---*/
10769 
10770  if (cg_ngrids(fn, i, j, &ngrids)) cg_error_exit();
10771  if (ngrids > 1) {
10772  SU2_MPI::Error("CGNS reader currently handles only 1 grid per zone.", CURRENT_FUNCTION);
10773  }
10774 
10775  /*--- Check the number of coordinate arrays stored in this zone.
10776  Should be 2 for 2-D grids and 3 for 3-D grids. ---*/
10777 
10778  if (cg_ncoords( fn, i, j, &ncoords)) cg_error_exit();
10779  if (rank == MASTER_NODE) {
10780  cout << "Reading grid coordinates." << endl;
10781  cout << "Number of coordinate dimensions is " << ncoords << "." << endl;
10782  }
10783 
10784  /*--- Compute the number of points that will be on each processor.
10785  This is a linear partitioning with the addition of a simple load
10786  balancing for any remainder points. ---*/
10787 
10788  total_pt_accounted = 0;
10789  for (int ii = 0; ii < size; ii++) {
10790  npoint_procs[ii] = vertices[j-1]/size;
10791  total_pt_accounted = total_pt_accounted + npoint_procs[ii];
10792  }
10793 
10794  /*--- Get the number of remainder points after the even division ---*/
10795 
10796  rem_points = vertices[j-1]-total_pt_accounted;
10797  for (unsigned long ii = 0; ii < rem_points; ii++) {
10798  npoint_procs[ii]++;
10799  }
10800 
10801  /*--- Store the local number of nodes and the beginning/end index ---*/
10802 
10804  starting_node[0] = 0;
10805  ending_node[0] = starting_node[0] + npoint_procs[0];
10806  nPoint_Linear[0] = 0;
10807  for (int ii = 1; ii < size; ii++) {
10808  starting_node[ii] = ending_node[ii-1];
10809  ending_node[ii] = starting_node[ii] + npoint_procs[ii];
10810  nPoint_Linear[ii] = nPoint_Linear[ii-1] + npoint_procs[ii-1];
10811  }
10812  nPoint_Linear[size] = vertices[j-1];
10813 
10814  /*--- Set the value of range_max to the total number of nodes in
10815  the unstructured mesh. Also allocate memory for the temporary array
10816  that will hold the grid coordinates as they are extracted. Note the
10817  +1 for CGNS convention. ---*/
10818 
10819  range_min = (cgsize_t)starting_node[rank]+1;
10820  range_max = (cgsize_t)ending_node[rank];
10821  coordArray[j-1] = new passivedouble[nPoint];
10822 
10823  /*--- Allocate memory for the 2-D array that will store the x, y,
10824  & z (if required) coordinates for writing into the SU2 mesh. ---*/
10825 
10826  gridCoords[j-1] = new passivedouble*[ncoords];
10827  for (int ii = 0; ii < ncoords; ii++) {
10828  *(gridCoords[j-1]+ii) = new passivedouble[nPoint];
10829  }
10830 
10831  /*--- Loop over each set of coordinates. Note again
10832  that the indexing starts at 1. ---*/
10833 
10834  for (int k = 1; k <= ncoords; k++) {
10835 
10836  /*--- Read the coordinate info. This will retrieve the
10837  data type (either RealSingle or RealDouble) as
10838  well as the coordname which will specifiy the
10839  type of data that it is based in the SIDS convention.
10840  This might be "CoordinateX," for instance. ---*/
10841 
10842  if (cg_coord_info(fn, i, j, k, &datatype, coordname))
10843  cg_error_exit();
10844  if (rank == MASTER_NODE) {
10845  cout << "Loading " << coordname;
10846  if (size > SINGLE_NODE) {
10847  cout << " values into linear partitions." << endl;
10848  } else {
10849  cout << " values." << endl;
10850  }
10851  }
10852 
10853  /*--- Always retrieve the grid coords in su2double precision. ---*/
10854 
10855  if (datatype != RealDouble) {
10856  SU2_MPI::Error("CGNS coordinates are not double precision.", CURRENT_FUNCTION);
10857  }
10858  if ( cg_coord_read(fn, i, j, coordname, datatype, &range_min,
10859  &range_max, coordArray[j-1]) ) cg_error_exit();
10860 
10861  /*--- Copy these coords into the array for storage until
10862  writing the SU2 mesh. ---*/
10863 
10864  for (unsigned long m = 0; m < nPoint; m++ ) {
10865  gridCoords[j-1][k-1][m] = coordArray[j-1][m];
10866  }
10867 
10868  }
10869 
10870  /*--- Begin section for retrieving the connectivity info. ---*/
10871 
10872  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
10873  cout << "Distributing connectivity across all ranks." << endl;
10874 
10875  /*--- First check the number of sections. ---*/
10876 
10877  if ( cg_nsections(fn, i, j, &nsections) ) cg_error_exit();
10878  if (rank == MASTER_NODE) {
10879  cout << "Number of connectivity sections is ";
10880  cout << nsections << "." << endl;
10881  }
10882 
10883  /*--- Allocate several data structures to hold the various
10884  pieces of information describing each section. It is
10885  stored in this manner so that it can be written to
10886  SU2 memory later. ---*/
10887 
10888  elemTypeVTK[j-1] = new int[nsections];
10889  elemIndex[j-1] = new int[nsections];
10890  elemBegin[j-1] = new int[nsections];
10891  elemEnd[j-1] = new int[nsections];
10892  nElems[j-1] = new int[nsections];
10893  dataSize[j-1] = new int[nsections];
10894  isInternal[j-1] = new bool[nsections];
10895 
10896  sectionNames[j-1] = new char*[nsections];
10897  for (int ii = 0; ii < nsections; ii++) {
10898  sectionNames[j-1][ii]= new char[CGNS_STRING_SIZE];
10899  }
10900 
10901  connElems[j-1] = new cgsize_t**[nsections];
10902 
10903  /*--- Loop over each section. This will include the main
10904  connectivity information for the grid cells, as well
10905  as any boundaries which were labeled before export. ---*/
10906 
10907  for (int s = 1; s <= nsections; s++) {
10908 
10909  connElems[j-1][s-1] = NULL;
10910  /*--- Read the connectivity details for this section.
10911  Store the total number of elements in this section
10912  to be used later for memory allocation. ---*/
10913 
10914  if (cg_section_read(fn, i, j, s, sectionNames[j-1][s-1],
10915  &elemType, &startE, &endE, &nbndry,
10916  &parent_flag)) cg_error_exit();
10917 
10918  /*--- Store the beginning and ending index for this section. ---*/
10919 
10920  elemBegin[j-1][s-1] = (int)startE;
10921  elemEnd[j-1][s-1] = (int)endE;
10922 
10923  /*--- Compute element linear partitioning ---*/
10924 
10925  element_count = (int) (endE-startE+1);
10926  total_elems = 0;
10927  for (int ii = 0; ii < size; ii++) {
10928  nElem_Linear[ii] = element_count/size;
10929  total_elems += nElem_Linear[ii];
10930  }
10931 
10932  /*--- Get the number of remainder elements after even division ---*/
10933 
10934  element_remainder = element_count-total_elems;
10935  for (unsigned long ii = 0; ii < element_remainder; ii++) {
10936  nElem_Linear[ii]++;
10937  }
10938 
10939  /*--- Store the number of elements that this rank is responsible for
10940  in the current section. ---*/
10941 
10942  nElems[j-1][s-1] = (int)nElem_Linear[rank];
10943 
10944  /*--- Get starting and end element index for my rank. ---*/
10945 
10946  elemB[0] = startE;
10947  elemE[0] = startE + nElem_Linear[0] - 1;
10948  for (unsigned long ii = 1; ii < (unsigned long)size; ii++) {
10949  elemB[ii] = elemE[ii-1]+1;
10950  elemE[ii] = elemB[ii] + nElem_Linear[ii] - 1;
10951  }
10952 
10953  /*--- Allocate some memory for the handling the connectivity
10954  and auxiliary data that we are need to communicate. ---*/
10955 
10956  connElemCGNS = new cgsize_t[nElems[j-1][s-1]*connSize];
10957  nPoinPerElem = new unsigned short[nElems[j-1][s-1]];
10958  elemGlobalID = new unsigned long[nElems[j-1][s-1]];
10959  elemTypes = new unsigned short[nElems[j-1][s-1]];
10960 
10961  isMixed = new bool[nElems[j-1][s-1]];
10962  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) isMixed[ii] = false;
10963 
10964  /*--- Protect against the situation where there are fewer elements
10965  in a section than number of ranks, or the linear partitioning will
10966  fail. For now, assume that these must be surfaces, and we will
10967  avoid a parallel read and have the master read this section (the
10968  master processes all of the markers anyway). ---*/
10969 
10970  if (nElems[j-1][s-1] < rank+1) {
10971 
10972  isInternal[j-1][s-1] = false;
10973 
10974  } else {
10975 
10976  /*--- Retrieve the connectivity information and store. Note that
10977  we are only accessing our rank's piece of the data here in the
10978  partial read function in the CGNS API. ---*/
10979 
10980  if (cg_elements_partial_read(fn, i, j, s, (cgsize_t)elemB[rank],
10981  (cgsize_t)elemE[rank], connElemCGNS,
10982  parentData) != CG_OK) cg_error_exit();
10983 
10984  /*--- Find the number of nodes required to represent
10985  this type of element. ---*/
10986 
10987  ElementType_t elmt_type;
10988  if (cg_npe(elemType, &npe)) cg_error_exit();
10989 
10990  /*--- Loop through all of the elements in this section to get more
10991  information and to decide whether it has internal elements. ---*/
10992 
10993  int counter = 0;
10994  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
10995 
10996  /*--- If we have a mixed element section, we need to check the elem
10997  type one by one. Set the flag to true if mixed. ---*/
10998 
10999  if (elemType == MIXED) {
11000  elmt_type = ElementType_t(connElemCGNS[counter]);
11001  cg_npe(elmt_type, &npe);
11002  counter++; for ( int jj = 0; jj < npe; jj++ ) counter++;
11003  isMixed[ii] = true;
11004  } else {
11005  elmt_type = elemType;
11006  }
11007 
11008  /*--- Store the number of verts per elem for the current elem. ---*/
11009 
11010  nPoinPerElem[ii] = npe;
11011 
11012  /*--- Store the global ID for this element. Note the -1 to move
11013  from CGNS convention to SU2 convention. We also subtract off
11014  an additional offset in case we have found boundary sections
11015  prior to this one, in order to keep the internal element global
11016  IDs indexed starting from zero. ---*/
11017 
11018  elemGlobalID[ii] = elemB[rank] + ii - 1 - globalOffset;
11019 
11020  /*--- Need to check the element type and correctly specify the
11021  VTK identifier for that element. SU2 recognizes elements by
11022  their VTK number. ---*/
11023 
11024  char buf1[100], buf2[100], buf3[100];
11025 
11026  switch (elmt_type) {
11027  case NODE:
11028  currentElem = "Vertex";
11029  elemTypes[ii] = 1;
11030  break;
11031  case BAR_2:
11032  currentElem = "Line";
11033  elemTypes[ii] = 3;
11034  break;
11035  case BAR_3:
11036  currentElem = "Line";
11037  elemTypes[ii] = 3;
11038  break;
11039  case TRI_3:
11040  currentElem = "Triangle";
11041  elemTypes[ii] = 5;
11042  break;
11043  case QUAD_4:
11044  currentElem = "Quadrilateral";
11045  elemTypes[ii] = 9;
11046  break;
11047  case TETRA_4:
11048  currentElem = "Tetrahedron";
11049  elemTypes[ii] = 10;
11050  break;
11051  case HEXA_8:
11052  currentElem = "Hexahedron";
11053  elemTypes[ii] = 12;
11054  break;
11055  case PENTA_6:
11056  currentElem = "Prism";
11057  elemTypes[ii] = 13;
11058  break;
11059  case PYRA_5:
11060  currentElem = "Pyramid";
11061  elemTypes[ii] = 14;
11062  break;
11063  case HEXA_20:
11064  SPRINTF(buf1, "Section %d, npe=%d\n", s, npe);
11065  SPRINTF(buf2, "startE %d, endE %d", (int)startE, (int)endE);
11066  SU2_MPI::Error(string("HEXA-20 element type not supported\n") +
11067  string(buf1) + string(buf2), CURRENT_FUNCTION);
11068  break;
11069  default:
11070  SPRINTF(buf1, "Unknown elem: (type %d, npe=%d)\n", elemType, npe);
11071  SPRINTF(buf2, "Section %d\n", s);
11072  SPRINTF(buf3, "startE %d, endE %d", (int)startE, (int)endE);
11073  SU2_MPI::Error(string(buf1) + string(buf2) + string(buf3), CURRENT_FUNCTION);
11074  break;
11075  }
11076 
11077  /*--- Check if the elements in this section are part
11078  of the internal domain or are part of the boundary
11079  surfaces. This will be used to separate the
11080  internal connectivity from the boundary connectivity.
11081  We will check for quad and tri elements for 3-D meshes
11082  because these will be the boundaries. Similarly, line
11083  elements will be boundaries to 2-D problems. ---*/
11084 
11085  if ( cell_dim == 2 ) {
11086 
11087  /*--- In 2-D check for line elements, VTK type 3. ---*/
11088 
11089  if (elemTypes[ii] == 3) {
11090  isInternal[j-1][s-1] = false;
11091  } else {
11092  isInternal[j-1][s-1] = true;
11093  interiorElems++;
11094  }
11095 
11096  } else if (cell_dim == 3) {
11097 
11098  /*--- In 3-D check for tri/quad elements, VTK types 5 or 9. ---*/
11099 
11100  switch (elemTypes[ii]) {
11101  case 5:
11102  case 9:
11103  isInternal[j-1][s-1] = false;
11104  break;
11105  default:
11106  isInternal[j-1][s-1] = true;
11107  interiorElems++;
11108  break;
11109  }
11110 
11111  }
11112  }
11113 
11114  /*--- Print some information to the console. ---*/
11115 
11116  if (rank == MASTER_NODE) {
11117  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ )
11118  if (isMixed[ii]) {currentElem = "Mixed"; break;}
11119  cout << "Loading section " << sectionNames[j-1][s-1];
11120  cout << " of element type " << currentElem << "." << endl;
11121  }
11122 
11123  }
11124 
11125  /*--- If we have found that this is a boundary section (we assume
11126  that internal cells and boundary cells do not exist in the same
11127  section together), the master node reads the boundary section.
11128  Otherwise, we have all ranks read and communicate the internals. ---*/
11129 
11130  if (!isInternal[j-1][s-1]) {
11131 
11132  /*--- Master node should read this entire marker section. Free
11133  the memory for the conn. from the CGNS file since we are going
11134  to read the section again with the master. ---*/
11135 
11136  delete [] connElemCGNS;
11137  delete [] nPoinPerElem;
11138  delete [] elemTypes;
11139  delete [] elemGlobalID;
11140  delete [] isMixed;
11141 
11142  /*--- Since we found an internal section, we should adjust the
11143  element global ID offset by the total size of the section. ---*/
11144 
11145  globalOffset += element_count;
11146 
11147  if (rank == MASTER_NODE) {
11148 
11149  /*--- First increment the markers ---*/
11150 
11151  nMarkers++;
11152 
11153  /*--- Read the section info again ---*/
11154 
11155  if ( cg_section_read(fn, i, j, s, sectionNames[j-1][s-1],
11156  &elemType, &startE, &endE, &nbndry,
11157  &parent_flag) ) cg_error_exit();
11158 
11159  /*--- Store the number of elems (all on the master). ---*/
11160 
11161  nElems[j-1][s-1] = (int) (endE-startE+1);
11162 
11163  /*--- Read and store the total amount of data that will be
11164  listed when reading this section. ---*/
11165 
11166  if (cg_ElementDataSize(fn, i, j, s, &ElementDataSize))
11167  cg_error_exit();
11168  dataSize[j-1][s-1] = ElementDataSize;
11169 
11170  /*--- Find the number of nodes required to represent
11171  this type of element. ---*/
11172 
11173  if (cg_npe(elemType, &npe)) cg_error_exit();
11174  elemIndex[j-1][s-1] = npe;
11175 
11176  /*--- Need to check the element type and correctly
11177  specify the VTK identifier for that element.
11178  SU2 recognizes elements by their VTK number. ---*/
11179 
11180  char buf1[100], buf2[100], buf3[100];
11181 
11182  switch (elemType) {
11183  case NODE:
11184  elemTypeVTK[j-1][s-1] = 1;
11185  break;
11186  case BAR_2:
11187  elemTypeVTK[j-1][s-1] = 3;
11188  break;
11189  case BAR_3:
11190  elemTypeVTK[j-1][s-1] = 3;
11191  break;
11192  case TRI_3:
11193  elemTypeVTK[j-1][s-1] = 5;
11194  break;
11195  case QUAD_4:
11196  elemTypeVTK[j-1][s-1] = 9;
11197  break;
11198  case TETRA_4:
11199  elemTypeVTK[j-1][s-1] = 10;
11200  break;
11201  case HEXA_8:
11202  elemTypeVTK[j-1][s-1] = 12;
11203  break;
11204  case PENTA_6:
11205  elemTypeVTK[j-1][s-1] = 13;
11206  break;
11207  case PYRA_5:
11208  elemTypeVTK[j-1][s-1] = 14;
11209  break;
11210  case HEXA_20:
11211  SPRINTF(buf1, "Section %d, npe=%d\n", s, npe);
11212  SPRINTF(buf2, "startE %d, endE %d", (int)startE, (int)endE);
11213  SU2_MPI::Error(string("HEXA-20 element type not supported\n") +
11214  string(buf1) + string(buf2), CURRENT_FUNCTION);
11215  break;
11216  case MIXED:
11217  currentElem = "Mixed";
11218  elemTypeVTK[j-1][s-1] = -1;
11219  break;
11220  default:
11221  SPRINTF(buf1, "Unknown elem: (type %d, npe=%d)\n", elemType, npe);
11222  SPRINTF(buf2, "Section %d\n", s);
11223  SPRINTF(buf3, "startE %d, endE %d", (int)startE, (int)endE);
11224  SU2_MPI::Error(string(buf1) + string(buf2) + string(buf3), CURRENT_FUNCTION);
11225  break;
11226  }
11227 
11228  /*--- In case of mixed data type, allocate place for 8 nodes
11229  maximum (hex), plus element type. ---*/
11230 
11231  if (elemTypeVTK[j-1][s-1] == -1) elemIndex[j-1][s-1] = 9;
11232 
11233  /*--- Allocate memory for accessing the connectivity and to
11234  store it in the proper data structure for post-processing. ---*/
11235 
11236  connElemTemp = new cgsize_t[dataSize[j-1][s-1]];
11237  connElems[j-1][s-1] = new cgsize_t*[elemIndex[j-1][s-1]];
11238  for (int jj = 0; jj < elemIndex[j-1][s-1]; jj++) {
11239  connElems[j-1][s-1][jj] = new cgsize_t[nElems[j-1][s-1]];
11240  }
11241 
11242  /*--- Retrieve the connectivity information and store. ---*/
11243 
11244  if (cg_elements_read(fn, i, j, s, connElemTemp, parentData))
11245  cg_error_exit();
11246 
11247  /*--- Copy these values into the larger array for
11248  storage until writing the SU2 file. ---*/
11249 
11250  if (elemTypeVTK[j-1][s-1] == -1) {
11251  int counter = 0;
11252  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
11253  ElementType_t elmt_type = ElementType_t(connElemTemp[counter]);
11254  cg_npe( elmt_type, &npe);
11255  counter++;
11256  connElems[j-1][s-1][0][ii] = elmt_type;
11257  for ( int jj = 0; jj < npe; jj++ ) {
11258  connElems[j-1][s-1][jj+1][ii] = connElemTemp[counter] - 1;
11259  counter++;
11260  }
11261  }
11262  } else {
11263  int counter = 0;
11264  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
11265  for ( int jj = 0; jj < elemIndex[j-1][s-1]; jj++ ) {
11266  connElems[j-1][s-1][jj][ii] = connElemTemp[counter] - 1;
11267  counter++;
11268  }
11269  }
11270  }
11271  delete[] connElemTemp;
11272 
11273  } // end master
11274 
11275  } else {
11276 
11277  /*--- These are internal elems. Allocate memory on each proc. ---*/
11278 
11279  connElemTemp = new cgsize_t[nElems[j-1][s-1]*connSize];
11280 
11281  /*--- Copy these values into the larger array for
11282  storage until writing the SU2 file. ---*/
11283 
11284  int counterTemp = 0, counterCGNS = 0;
11285  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
11286 
11287  /*--- Store the conn in chunks of connSize for simplicity. ---*/
11288 
11289  counterTemp = ii*connSize;
11290 
11291  /*--- Store the connectivity values. Note we subtract one from
11292  the CGNS 1-based convention. We may also need to remove the first
11293  entry is this is a mixed element section. ---*/
11294 
11295  if (isMixed[ii]) counterCGNS++;
11296  for ( int jj = 0; jj < nPoinPerElem[ii]; jj++) {
11297  connElemTemp[counterTemp] = connElemCGNS[counterCGNS + jj] - 1;
11298  counterTemp++;
11299  }
11300  counterCGNS += nPoinPerElem[ii];
11301 
11302  }
11303 
11304  /*--- Free the memory for the conn. from the CGNS file. ---*/
11305 
11306  delete [] connElemCGNS;
11307  delete [] isMixed;
11308 
11309  /*--- We now have the connectivity stored in linearly partitioned
11310  chunks. We need to loop through and decide how many elements we
11311  must send to each rank in order to have all elements that
11312  surround a particular "owned" node on each rank (i.e., elements
11313  will appear on multiple ranks). First, initialize a counter
11314  and flag. ---*/
11315 
11316  int *nElem_Send = new int[size+1]; nElem_Send[0] = 0;
11317  int *nElem_Recv = new int[size+1]; nElem_Recv[0] = 0;
11318  int *nElem_Flag = new int[size];
11319 
11320  for (int ii=0; ii < size; ii++) {
11321  nElem_Send[ii] = 0;
11322  nElem_Recv[ii] = 0;
11323  nElem_Flag[ii]= -1;
11324  }
11325  nElem_Send[size] = 0; nElem_Recv[size] = 0;
11326 
11327  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
11328  for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) {
11329 
11330  /*--- Get the index of the current point. ---*/
11331 
11332  iPoint = connElemTemp[ii*connSize + jj];
11333 
11334  /*--- Search for the processor that owns this point ---*/
11335 
11336  iProcessor = iPoint/npoint_procs[0];
11337  if (iProcessor >= (unsigned long)size)
11338  iProcessor = (unsigned long)size-1;
11339  if (iPoint >= nPoint_Linear[iProcessor])
11340  while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++;
11341  else
11342  while(iPoint < nPoint_Linear[iProcessor]) iProcessor--;
11343 
11344  /*--- If we have not visited this element yet, increment our
11345  number of elements that must be sent to a particular proc. ---*/
11346 
11347  if (nElem_Flag[iProcessor] != ii) {
11348  nElem_Flag[iProcessor] = ii;
11349  nElem_Send[iProcessor+1]++;
11350  }
11351 
11352  }
11353  }
11354 
11355  /*--- Communicate the number of cells to be sent/recv'd amongst
11356  all processors. After this communication, each proc knows how
11357  many cells it will receive from each other processor. ---*/
11358 
11359 #ifdef HAVE_MPI
11360  SU2_MPI::Alltoall(&(nElem_Send[1]), 1, MPI_INT,
11361  &(nElem_Recv[1]), 1, MPI_INT, MPI_COMM_WORLD);
11362 #else
11363  nElem_Recv[1] = nElem_Send[1];
11364 #endif
11365 
11366  /*--- Prepare to send connectivities. First check how many
11367  messages we will be sending and receiving. Here we also put
11368  the counters into cumulative storage format to make the
11369  communications simpler. ---*/
11370 
11371  int nSends = 0, nRecvs = 0;
11372  for (int ii=0; ii < size; ii++) nElem_Flag[ii] = -1;
11373 
11374  for (int ii = 0; ii < size; ii++) {
11375 
11376  if ((ii != rank) && (nElem_Send[ii+1] > 0)) nSends++;
11377  if ((ii != rank) && (nElem_Recv[ii+1] > 0)) nRecvs++;
11378 
11379  nElem_Send[ii+1] += nElem_Send[ii];
11380  nElem_Recv[ii+1] += nElem_Recv[ii];
11381  }
11382 
11383  /*--- Allocate memory to hold the connectivity that we are
11384  sending. Note that we are also sending the VTK element type
11385  in the first position and also the global ID. We have assumed
11386  a constant message size of a hex element + 2 extra vals. ---*/
11387 
11388  unsigned long *connSend = NULL;
11389  connSend = new unsigned long[connSize*nElem_Send[size]];
11390  for (int ii = 0; ii < connSize*nElem_Send[size]; ii++)
11391  connSend[ii] = 0;
11392 
11393  /*--- Create an index variable to keep track of our index
11394  position as we load up the send buffer. ---*/
11395 
11396  unsigned long *index = new unsigned long[size];
11397  for (int ii=0; ii < size; ii++) index[ii] = connSize*nElem_Send[ii];
11398 
11399  /*--- Loop through our elements and load the elems and their
11400  additional data that we will send to the other procs. ---*/
11401 
11402  for ( int ii = 0; ii < nElems[j-1][s-1]; ii++ ) {
11403  for ( int jj = 0; jj < nPoinPerElem[ii]; jj++ ) {
11404 
11405  /*--- Get the index of the current point. ---*/
11406 
11407  iPoint = connElemTemp[ii*connSize + jj];
11408 
11409  /*--- Search for the processor that owns this point ---*/
11410 
11411  iProcessor = iPoint/npoint_procs[0];
11412  if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1;
11413  if (iPoint >= nPoint_Linear[iProcessor])
11414  while(iPoint >= nPoint_Linear[iProcessor+1]) iProcessor++;
11415  else
11416  while(iPoint < nPoint_Linear[iProcessor]) iProcessor--;
11417 
11418  /*--- Load connectivity into the buffer for sending ---*/
11419 
11420  if (nElem_Flag[iProcessor] != ii) {
11421 
11422  nElem_Flag[iProcessor] = ii;
11423  unsigned long nn = index[iProcessor];
11424 
11425  /*--- Load the VTK type first into the conn array,
11426  then the connectivity vals, and last, the global ID. ---*/
11427 
11428  connSend[nn] = elemTypes[ii]; nn++;
11429  for ( int kk = 0; kk < nPoinPerElem[ii]; kk++ ) {
11430  connSend[nn] = connElemTemp[ii*connSize + kk]; nn++;
11431  }
11432  connSend[nn] = (cgsize_t)elemGlobalID[ii];
11433 
11434  /*--- Increment the index by the message length ---*/
11435 
11436  index[iProcessor] += connSize;
11437 
11438  }
11439  }
11440  }
11441 
11442  /*--- Free memory after loading up the send buffer. ---*/
11443 
11444  delete [] connElemTemp;
11445  delete [] elemTypes;
11446  delete [] nPoinPerElem;
11447  delete [] elemGlobalID;
11448  delete [] index;
11449 
11450  /*--- Allocate the memory that we need for receiving the conn
11451  values and then cue up the non-blocking receives. Note that
11452  we do not include our own rank in the communications. We will
11453  directly copy our own data later. ---*/
11454 
11455  unsigned long *connRecv = NULL;
11456  connRecv = new unsigned long[connSize*nElem_Recv[size]];
11457  for (int ii = 0; ii < connSize*nElem_Recv[size]; ii++)
11458  connRecv[ii] = 0;
11459 
11460 #ifdef HAVE_MPI
11461  send_req = new SU2_MPI::Request[nSends];
11462  recv_req = new SU2_MPI::Request[nRecvs];
11463  unsigned long iMessage = 0;
11464  for (int ii=0; ii<size; ii++) {
11465  if ((ii != rank) && (nElem_Recv[ii+1] > nElem_Recv[ii])) {
11466  int ll = connSize*nElem_Recv[ii];
11467  int kk = nElem_Recv[ii+1] - nElem_Recv[ii];
11468  int count = connSize*kk;
11469  int source = ii;
11470  int tag = ii + 1;
11471  SU2_MPI::Irecv(&(connRecv[ll]), count, MPI_UNSIGNED_LONG, source, tag,
11472  MPI_COMM_WORLD, &(recv_req[iMessage]));
11473  iMessage++;
11474  }
11475  }
11476 
11477  /*--- Launch the non-blocking sends of the connectivity. ---*/
11478 
11479  iMessage = 0;
11480  for (int ii=0; ii<size; ii++) {
11481  if ((ii != rank) && (nElem_Send[ii+1] > nElem_Send[ii])) {
11482  int ll = connSize*nElem_Send[ii];
11483  int kk = nElem_Send[ii+1] - nElem_Send[ii];
11484  int count = connSize*kk;
11485  int dest = ii;
11486  int tag = rank + 1;
11487  SU2_MPI::Isend(&(connSend[ll]), count, MPI_UNSIGNED_LONG, dest, tag,
11488  MPI_COMM_WORLD, &(send_req[iMessage]));
11489  iMessage++;
11490  }
11491  }
11492 #endif
11493 
11494  /*--- Copy my own rank's data into the recv buffer directly. ---*/
11495 
11496  int mm = connSize*nElem_Recv[rank];
11497  int ll = connSize*nElem_Send[rank];
11498  int kk = connSize*nElem_Send[rank+1];
11499 
11500  for (int nn=ll; nn<kk; nn++, mm++) connRecv[mm] = connSend[nn];
11501 
11502  /*--- Wait for the non-blocking sends and recvs to complete ---*/
11503 
11504 #ifdef HAVE_MPI
11505  int number = nSends;
11506  for (int ii = 0; ii < nSends; ii++)
11507  SU2_MPI::Waitany(number, send_req, &ind, &status);
11508 
11509  number = nRecvs;
11510  for (int ii = 0; ii < nRecvs; ii++)
11511  SU2_MPI::Waitany(number, recv_req, &ind, &status);
11512 
11513  delete [] send_req;
11514  delete [] recv_req;
11515 #endif
11516 
11517  /*--- Store the connectivity for this rank in the proper data
11518  structure before post-processing below. First, allocate the
11519  appropriate amount of memory for this section. ---*/
11520 
11521  connElems[j-1][s-1] = new cgsize_t*[connSize];
11522  for (int jj = 0; jj < connSize; jj++) {
11523  connElems[j-1][s-1][jj] = new cgsize_t[nElem_Recv[size]];
11524  }
11525  for (int ii = 0; ii < nElem_Recv[size]; ii++) {
11526  for (int jj = 0; jj < connSize; jj++) {
11527  connElems[j-1][s-1][jj][ii] = (cgsize_t)connRecv[ii*connSize+jj];
11528  }
11529  }
11530 
11531  /*--- Store the total number of elements I now have for
11532  the current section after completing the communications. ---*/
11533 
11534  nElems[j-1][s-1] = nElem_Recv[size];
11535 
11536  /*--- Free temporary memory from communications ---*/
11537 
11538  delete [] connSend;
11539  delete [] connRecv;
11540  delete [] nElem_Recv;
11541  delete [] nElem_Send;
11542  delete [] nElem_Flag;
11543 
11544  }
11545 
11546  } // end section
11547 
11548  } // end zone
11549 
11550  } // end database
11551 
11552  /*--- Close the CGNS file. ---*/
11553 
11554  if ( cg_close(fn) ) cg_error_exit();
11555  if (rank == MASTER_NODE)
11556  cout << "Successfully closed the CGNS file." << endl;
11557 
11558  /*--- Load the data from the CGNS file into SU2 memory. ---*/
11559 
11560  if (rank == MASTER_NODE)
11561  cout << endl << "Loading CGNS data into SU2 data structures." << endl;
11562 
11563  /*--- Read the dimension of the problem ---*/
11564 
11565  nDim = cell_dim;
11566  if (rank == MASTER_NODE) {
11567  if (nDim == 2) cout << "Two dimensional problem." << endl;
11568  if (nDim == 3) cout << "Three dimensional problem." << endl;
11569  }
11570 
11571  /*--- Initialize an array for the adjacency information (ParMETIS). ---*/
11572 
11573  vector< vector<unsigned long> > adj_nodes(nPoint, vector<unsigned long>(0));
11574 
11575  /*--- Loop to check total number of elements we have locally. ---*/
11576 
11577  ielem = 0;
11578  for (int k = 0; k < nzones; k++) {
11579  for (int s = 0; s < nsections; s++) {
11580  if (isInternal[k][s]) {
11581  for ( int i = 0; i < nElems[k][s]; i++) {
11582  ielem++;
11583  }
11584  }
11585  }
11586  }
11587  nElem = ielem;
11588 
11589  /*--- Store the total number of interior elements (global). ---*/
11590 
11591 #ifdef HAVE_MPI
11592  Local_nElem = interiorElems;
11595 #else
11596  Global_nElem = interiorElems;
11597  nElem = Global_nElem;
11598 #endif
11599 
11600  if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) {
11601  cout << Global_nElem << " interior elements before linear partitioning." << endl;
11602  } else if (rank == MASTER_NODE) {
11603  cout << Global_nElem << " interior elements." << endl;
11604  }
11605 
11606  /*--- Set up the global to local element mapping. ---*/
11607  Global_to_Local_Elem.clear();
11608 
11609  /*--- Allocate space for elements. We allocate enough for all interior
11610  elements globally, but we will only instantiate our local set. ---*/
11611 
11612  elem = new CPrimalGrid*[nElem];
11613  ielem = 0;
11614  unsigned long global_id = 0;
11615 
11616  /*--- Loop over all the internal, local volumetric elements. ---*/
11617 
11618  for (int k = 0; k < nzones; k++) {
11619  for (int s = 0; s < nsections; s++) {
11620  if (isInternal[k][s]) {
11621  for ( int i = 0; i < nElems[k][s]; i++) {
11622 
11623  /*--- Get the VTK type for this element. This is stored in the
11624  first entry of the connectivity structure. ---*/
11625 
11626  VTK_Type = connElems[k][s][0][i];
11627 
11628  /*--- Instantiate this element and build adjacency structure. ---*/
11629 
11630  switch(VTK_Type) {
11631 
11632  case TRIANGLE:
11633 
11634  for ( unsigned short j = 0; j < N_POINTS_TRIANGLE; j++ ) {
11635  vnodes_cgns[j] = connElems[k][s][j+1][i];
11636  }
11637  global_id = connElems[k][s][N_POINTS_TRIANGLE+1][i];
11638  for (unsigned short ii=0; ii<N_POINTS_TRIANGLE; ii++) {
11639  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11640  for (unsigned short j=0; j<N_POINTS_TRIANGLE; j++) {
11641  if (ii!=j) {
11642  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[j]);
11643  }
11644  }
11645  }
11646  }
11647  Global_to_Local_Elem[global_id]=ielem;
11648  elem[ielem] = new CTriangle(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], nDim);
11649  ielem++; nelem_triangle++;
11650  break;
11651 
11652  case QUADRILATERAL:
11653 
11654  for ( unsigned short j = 0; j < N_POINTS_QUADRILATERAL; j++ ) {
11655  vnodes_cgns[j] = connElems[k][s][j+1][i];
11656  }
11657  global_id = connElems[k][s][N_POINTS_QUADRILATERAL+1][i];
11658 
11659  for (unsigned short ii=0; ii<N_POINTS_QUADRILATERAL; ii++) {
11660  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11661 
11662  /*--- Build adjacency assuming the VTK connectivity ---*/
11663 
11664  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+1)%4]);
11665  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+3)%4]);
11666 
11667  }
11668  }
11669 
11670  Global_to_Local_Elem[global_id]=ielem;
11671  elem[ielem] = new CQuadrilateral(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3], nDim);
11672  ielem++; nelem_quad++;
11673  break;
11674 
11675  case TETRAHEDRON:
11676 
11677  for ( unsigned short j = 0; j < N_POINTS_TETRAHEDRON; j++ ) {
11678  vnodes_cgns[j] = connElems[k][s][j+1][i];
11679  }
11680  global_id = connElems[k][s][N_POINTS_TETRAHEDRON+1][i];
11681  for (unsigned short ii=0; ii<N_POINTS_TETRAHEDRON; ii++) {
11682  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11683  for (unsigned short j=0; j<N_POINTS_TETRAHEDRON; j++) {
11684  if (ii!=j) {
11685  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[j]);
11686  }
11687  }
11688  }
11689  }
11690  Global_to_Local_Elem[global_id]=ielem;
11691  elem[ielem] = new CTetrahedron(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3]);
11692  ielem++; nelem_tetra++;
11693  break;
11694 
11695  case HEXAHEDRON:
11696 
11697  for ( unsigned short j = 0; j < N_POINTS_HEXAHEDRON; j++ ) {
11698  vnodes_cgns[j] = connElems[k][s][j+1][i];
11699  }
11700  global_id = connElems[k][s][N_POINTS_HEXAHEDRON+1][i];
11701 
11702  for (unsigned short ii=0; ii<N_POINTS_HEXAHEDRON; ii++) {
11703  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11704 
11705  /*--- Build adjacency assuming the VTK connectivity ---*/
11706 
11707  if (ii < 4) {
11708  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+1)%4]);
11709  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+3)%4]);
11710  } else {
11711  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii-3)%4+4]);
11712  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii-1)%4+4]);
11713  }
11714  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+4)%8]);
11715 
11716  }
11717  }
11718 
11719  Global_to_Local_Elem[global_id]=ielem;
11720  elem[ielem] = new CHexahedron(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3], vnodes_cgns[4], vnodes_cgns[5], vnodes_cgns[6], vnodes_cgns[7]);
11721  ielem++; nelem_hexa++;
11722  break;
11723 
11724  case PRISM:
11725 
11726  for ( unsigned short j = 0; j < N_POINTS_PRISM; j++ ) {
11727  vnodes_cgns[j] = connElems[k][s][j+1][i];
11728  }
11729  global_id = connElems[k][s][N_POINTS_PRISM+1][i];
11730 
11731  for (unsigned short ii=0; ii<N_POINTS_PRISM; ii++) {
11732  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11733 
11734  /*--- Build adjacency assuming the VTK connectivity ---*/
11735 
11736  if (ii < 3) {
11737  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+1)%3]);
11738  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+2)%3]);
11739  } else {
11740  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii-2)%3+3]);
11741  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii-1)%3+3]);
11742  }
11743  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+3)%6]);
11744 
11745  }
11746  }
11747 
11748  Global_to_Local_Elem[global_id]=ielem;
11749  elem[ielem] = new CPrism(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3], vnodes_cgns[4], vnodes_cgns[5]);
11750  ielem++; nelem_prism++;
11751  break;
11752 
11753  case PYRAMID:
11754 
11755  for ( unsigned short j = 0; j < N_POINTS_PYRAMID; j++ ) {
11756  vnodes_cgns[j] = connElems[k][s][j+1][i];
11757  }
11758  global_id = connElems[k][s][N_POINTS_PYRAMID+1][i];
11759 
11760  for (unsigned short ii=0; ii<N_POINTS_PYRAMID; ii++) {
11761  if ((vnodes_cgns[ii]>=starting_node[rank])&&(vnodes_cgns[ii]<ending_node[rank])) {
11762 
11763  /*--- Build adjacency assuming the VTK connectivity ---*/
11764 
11765  if (ii < 4) {
11766  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+1)%4]);
11767  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[(ii+3)%4]);
11768  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[4]);
11769  } else {
11770  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[0]);
11771  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[1]);
11772  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[2]);
11773  adj_nodes[vnodes_cgns[ii]-starting_node[rank]].push_back(vnodes_cgns[3]);
11774  }
11775 
11776  }
11777  }
11778 
11779  Global_to_Local_Elem[global_id]=ielem;
11780  elem[ielem] = new CPyramid(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3], vnodes_cgns[4]);
11781  ielem++; nelem_pyramid++;
11782  break;
11783 
11784  default:
11785  SU2_MPI::Error("Element type not supported!", CURRENT_FUNCTION);
11786  break;
11787  }
11788  }
11789  }
11790  }
11791  }
11792 
11793 #ifdef HAVE_MPI
11794  Local_nElemTri = nelem_triangle;
11795  Local_nElemQuad = nelem_quad;
11796  Local_nElemTet = nelem_tetra;
11797  Local_nElemHex = nelem_hexa;
11798  Local_nElemPrism = nelem_prism;
11799  Local_nElemPyramid = nelem_pyramid;
11800  SU2_MPI::Allreduce(&Local_nElemTri, &Global_nelem_triangle, 1,
11802  SU2_MPI::Allreduce(&Local_nElemQuad, &Global_nelem_quad, 1,
11804  SU2_MPI::Allreduce(&Local_nElemTet, &Global_nelem_tetra, 1,
11806  SU2_MPI::Allreduce(&Local_nElemHex, &Global_nelem_hexa, 1,
11808  SU2_MPI::Allreduce(&Local_nElemPrism, &Global_nelem_prism, 1,
11810  SU2_MPI::Allreduce(&Local_nElemPyramid, &Global_nelem_pyramid, 1,
11812 #else
11819 #endif
11820 
11821 #ifdef HAVE_MPI
11822 #ifdef HAVE_PARMETIS
11823 
11824  /*--- Post process the adjacency information in order to get it into the
11825  proper format before sending the data to ParMETIS. We need to remove
11826  repeats and adjust the size of the array for each local node. ---*/
11827 
11828  if ((rank == MASTER_NODE) && (size > SINGLE_NODE))
11829  cout << "Building the graph adjacency structure." << endl;
11830 
11831  unsigned long loc_adjc_size=0;
11832  vector<unsigned long> adjac_vec;
11833  unsigned long adj_elem_size;
11834  vector<unsigned long>::iterator it;
11835 
11836  xadj = new idx_t[npoint_procs[rank]+1];
11837  xadj[0]=0;
11838  vector<unsigned long> temp_adjacency;
11839  unsigned long local_count=0;
11840 
11841  for (unsigned long i = 0; i < nPoint; i++) {
11842 
11843  for (unsigned long j=0; j<adj_nodes[i].size(); j++) {
11844  temp_adjacency.push_back(adj_nodes[i][j]);
11845  }
11846 
11847  sort(temp_adjacency.begin(), temp_adjacency.end());
11848  it = unique( temp_adjacency.begin(), temp_adjacency.end());
11849  loc_adjc_size=it - temp_adjacency.begin();
11850 
11851  temp_adjacency.resize( loc_adjc_size);
11852  xadj[local_count+1]=xadj[local_count]+loc_adjc_size;
11853  local_count++;
11854 
11855  for (unsigned long j=0; j<loc_adjc_size; j++) {
11856  adjac_vec.push_back(temp_adjacency[j]);
11857  }
11858  temp_adjacency.clear();
11859  adj_nodes[i].clear();
11860  }
11861 
11862  /*--- Now that we know the size, create the final adjacency array ---*/
11863 
11864  adj_elem_size = xadj[npoint_procs[rank]];
11865  adjacency = new idx_t [adj_elem_size];
11866  copy(adjac_vec.begin(), adjac_vec.end(), adjacency);
11867 
11869  adjacency_size = adj_elem_size;
11870 
11871  /*--- Free temporary memory used to build the adjacency. ---*/
11872 
11873  adjac_vec.clear();
11874 
11875 #endif
11876 #endif
11877 
11878  adj_nodes.clear();
11879 
11880  /*--- Store the nodal coordinates from the linear partitioning. ---*/
11881 
11882  if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) {
11883  cout << Global_nPoint << " grid points before linear partitioning." << endl;
11884  } else if (rank == MASTER_NODE) {
11885  cout << Global_nPoint << " grid points." << endl;
11886  }
11887 
11888  iPoint = 0;
11889  nPointNode = nPoint;
11890  node = new CPoint*[nPoint];
11891  GlobalIndex = starting_node[rank];
11892  for (int k = 0; k < nzones; k++ ) {
11893  for (unsigned long i = 0; i < nPoint; i++ ) {
11894  for (int j = 0; j < cell_dim; j++ ) Coord_cgns[j] = gridCoords[k][j][i];
11895  switch(nDim) {
11896  case 2:
11897  node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], GlobalIndex, config);
11898  iPoint++; break;
11899  case 3:
11900  node[iPoint] = new CPoint(Coord_cgns[0], Coord_cgns[1], Coord_cgns[2], GlobalIndex, config);
11901  iPoint++; break;
11902  }
11903  GlobalIndex++;
11904  }
11905  }
11906 
11907  /*--- For now, the master node takes care of all markers. ---*/
11908 
11909  if (rank == MASTER_NODE) {
11910 
11911  /*--- Read number of markers ---*/
11912 
11913  nMarker = nMarkers;
11914  cout << nMarker << " surface markers." << endl;
11915  config->SetnMarker_All(nMarker);
11916  bound = new CPrimalGrid**[nMarker];
11917  nElem_Bound = new unsigned long [nMarker];
11918  Tag_to_Marker = new string [nMarker_Max];
11919 
11920  iMarker = 0;
11921  for ( int k = 0; k < nzones; k ++ ) {
11922  for ( int s = 0; s < nsections; s++ ) {
11923  if ( !isInternal[k][s] ) {
11924 
11925  /*--- Initialize some counter variables ---*/
11926 
11928  nelem_quad_bound = 0; ielem = 0;
11929 
11930  Marker_Tag = sectionNames[k][s];
11931 
11932  /*--- Remove whitespaces from the marker names ---*/
11933  Marker_Tag.erase(remove(Marker_Tag.begin(), Marker_Tag.end(),' '), Marker_Tag.end());
11934 
11935  if (Marker_Tag != "SEND_RECEIVE") {
11936  nElem_Bound[iMarker] = nElems[k][s];
11937  if (rank == MASTER_NODE) {
11938  cout << nElem_Bound[iMarker] << " boundary elements in index ";
11939  cout << iMarker <<" (Marker = " <<Marker_Tag<< ")." << endl;
11940  }
11941  bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]];
11942 
11943  for ( int i = 0; i < nElems[k][s]; i++ ) {
11944 
11945  /*--- Get the VTK type for this element. Check for mixed
11946  elements. ---*/
11947 
11948  if (elemTypeVTK[k][s] == -1 ) {
11949 
11950  /*--- Mixed-element support. Check the elem type. ---*/
11951 
11952  ElementType_t elmt_type = ElementType_t(connElems[k][s][0][i]);
11953  cg_npe( elmt_type, &npe);
11954 
11955  switch (elmt_type) {
11956  case NODE: VTK_Type = 1; break;
11957  case BAR_2: VTK_Type = 3; break;
11958  case BAR_3: VTK_Type = 3; break;
11959  case TRI_3: VTK_Type = 5; break;
11960  case QUAD_4: VTK_Type = 9; break;
11961  case TETRA_4: VTK_Type = 10; break;
11962  case HEXA_8: VTK_Type = 12; break;
11963  case PENTA_6: VTK_Type = 13; break;
11964  case PYRA_5: VTK_Type = 14; break;
11965  default:
11966  SU2_MPI::Error("Kind of element not suppported!", CURRENT_FUNCTION);
11967  break;
11968  }
11969 
11970  /*--- Transfer the nodes for this element. ---*/
11971 
11972  for ( int j = 1; j < npe+1; j++ ) {
11973  vnodes_cgns[j-1] = connElems[k][s][j][i];
11974  }
11975 
11976  } else {
11977 
11978  /*--- Not a mixed section. We know the element type. ---*/
11979 
11980  VTK_Type = elemTypeVTK[k][s];
11981 
11982  /*--- Transfer the nodes for this element. ---*/
11983 
11984  for ( int j = 0; j < elemIndex[k][s]; j++ ) {
11985  vnodes_cgns[j] = connElems[k][s][j][i];
11986  }
11987 
11988  }
11989 
11990  /*--- Instantiate the boundary elements. ---*/
11991 
11992  switch(VTK_Type) {
11993  case LINE:
11994  if (nDim == 3) {
11995  SU2_MPI::Error("Remove line boundary elems from the mesh.", CURRENT_FUNCTION);
11996  }
11997  bound[iMarker][ielem] = new CLine(vnodes_cgns[0], vnodes_cgns[1],2);
11998  ielem++; nelem_edge_bound++; break;
11999  case TRIANGLE:
12000  bound[iMarker][ielem] = new CTriangle(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2],3);
12001  ielem++; nelem_triangle_bound++; break;
12002  case QUADRILATERAL:
12003  bound[iMarker][ielem] = new CQuadrilateral(vnodes_cgns[0], vnodes_cgns[1], vnodes_cgns[2], vnodes_cgns[3],3);
12004  ielem++; nelem_quad_bound++; break;
12005  }
12006  }
12007 
12008  /*--- Update config information storing the boundary information in the right place ---*/
12009 
12010  Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag;
12011  config->SetMarker_All_TagBound(iMarker, Marker_Tag);
12012  config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag));
12013  config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag));
12014  config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag));
12015  config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag));
12016  config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag));
12017  config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag));
12018  config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag));
12019  config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag));
12020  config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag));
12021  config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag));
12022  config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag));
12023  config->SetMarker_All_SendRecv(iMarker, NONE);
12024  config->SetMarker_All_Turbomachinery(iMarker, config->GetMarker_CfgFile_Turbomachinery(Marker_Tag));
12025  config->SetMarker_All_TurbomachineryFlag(iMarker, config->GetMarker_CfgFile_TurbomachineryFlag(Marker_Tag));
12026  config->SetMarker_All_MixingPlaneInterface(iMarker, config->GetMarker_CfgFile_MixingPlaneInterface(Marker_Tag));
12027 
12028  }
12029  iMarker++;
12030  }
12031  }
12032  }
12033 
12034  }
12035 
12036  /*--- Periodic transformations are not implemented yet for CGNS.
12037  Store default zeros. ---*/
12038 
12039  unsigned short nPeriodic = 1, iPeriodic = 0;
12040  config->SetnPeriodicIndex(nPeriodic);
12041  su2double* center = new su2double[3];
12042  su2double* rotation = new su2double[3];
12043  su2double* translate = new su2double[3];
12044  for (unsigned short iDim = 0; iDim < 3; iDim++) {
12045  center[iDim] = 0.0; rotation[iDim] = 0.0; translate[iDim] = 0.0;
12046  }
12047  config->SetPeriodicCenter(iPeriodic, center);
12048  config->SetPeriodicRotation(iPeriodic, rotation);
12049  config->SetPeriodicTranslate(iPeriodic, translate);
12050  delete [] center; delete [] rotation; delete [] translate;
12051 
12052  /*--- Deallocate temporary memory. ---*/
12053 
12054  delete[] vertices;
12055  delete[] cells;
12056  delete[] boundVerts;
12057 
12058  for ( int kk = 0; kk < nzones; kk++) {
12059  for (int ii = 0; ii < nsections; ii++) {
12060  if (isInternal[kk][ii]) {
12061  for (int jj = 0; jj < connSize; jj++) {
12062  if (connElems[kk][ii][jj] != NULL) delete [] connElems[kk][ii][jj];
12063  }
12064  if (connElems[kk][ii] != NULL) delete [] connElems[kk][ii];
12065  } else if (!isInternal[kk][ii] && rank == MASTER_NODE) {
12066  for (int jj = 0; jj < elemIndex[kk][ii]; jj++) {
12067  if (connElems[kk][ii][jj] != NULL) delete [] connElems[kk][ii][jj];
12068  }
12069  if (connElems[kk][ii] != NULL) delete [] connElems[kk][ii];
12070  }
12071  }
12072  if (connElems[kk] != NULL) delete [] connElems[kk];
12073  }
12074  if (connElems != NULL) delete[] connElems;
12075 
12076  for ( int j = 0; j < nzones; j++) {
12077  delete [] coordArray[j];
12078  delete [] elemTypeVTK[j];
12079  delete [] elemIndex[j];
12080  delete [] nElems[j];
12081  delete [] dataSize[j];
12082  delete [] isInternal[j];
12083  delete [] elemBegin[j];
12084  delete [] elemEnd[j];
12085  for (int ii = 0; ii < nsections; ii++) {
12086  delete[] sectionNames[j][ii];
12087  }
12088  delete[] sectionNames[j];
12089  }
12090 
12091  delete [] coordArray;
12092  delete [] elemTypeVTK;
12093  delete [] elemIndex;
12094  delete [] nElems;
12095  delete [] dataSize;
12096  delete [] isInternal;
12097  delete [] sectionNames;
12098  delete [] elemBegin;
12099  delete [] elemEnd;
12100 
12101  for ( int j = 0; j < nzones; j++) {
12102  for ( int i = 0; i < ncoords; i++ ) {
12103  delete [] gridCoords[j][i];
12104  }
12105  delete [] gridCoords[j];
12106  }
12107  delete [] gridCoords;
12108 
12109  delete [] nElem_Linear;
12110 
12111  delete [] elemB;
12112  delete [] elemE;
12113 
12114  delete [] cgsize;
12115 
12116 #else
12117  SU2_MPI::Error(string("SU2 built without CGNS support!!\n") +
12118  string("To use CGNS, remove the -DNO_CGNS directive ") +
12119  string("from the makefile and supply the correct path ") +
12120  string("to the CGNS library."), CURRENT_FUNCTION);
12121 #endif
12122 
12123 }
12124 
12126 
12127  unsigned long Point_1, Point_2, Point_3, Point_4, Point_5, Point_6,
12128  iElem, triangle_flip = 0, quad_flip = 0, tet_flip = 0, prism_flip = 0,
12129  hexa_flip = 0, pyram_flip = 0;
12130  su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4,
12131  *Coord_5, *Coord_6, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test;
12132  unsigned short iDim;
12133 
12134  /*--- Loop over all the elements ---*/
12135 
12136  for (iElem = 0; iElem < nElem; iElem++) {
12137 
12138  /*--- 2D grid, triangle case ---*/
12139 
12140  if (elem[iElem]->GetVTK_Type() == TRIANGLE) {
12141 
12142  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12143  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12144  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12145 
12146  for (iDim = 0; iDim < nDim; iDim++) {
12147  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12148  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); }
12149  test = a[0]*b[1]-b[0]*a[1];
12150 
12151  if (test < 0.0) {
12152  elem[iElem]->Change_Orientation();
12153  triangle_flip++;
12154  }
12155  }
12156 
12157  /*--- 2D grid, quadrilateral case ---*/
12158 
12159  if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) {
12160 
12161  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12162  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12163  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12164  Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord();
12165 
12166  for (iDim = 0; iDim < nDim; iDim++) {
12167  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12168  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); }
12169  test_1 = a[0]*b[1]-b[0]*a[1];
12170 
12171  for (iDim = 0; iDim < nDim; iDim++) {
12172  a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]);
12173  b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); }
12174  test_2 = a[0]*b[1]-b[0]*a[1];
12175 
12176  for (iDim = 0; iDim < nDim; iDim++) {
12177  a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]);
12178  b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); }
12179  test_3 = a[0]*b[1]-b[0]*a[1];
12180 
12181  for (iDim = 0; iDim < nDim; iDim++) {
12182  a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]);
12183  b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); }
12184  test_4 = a[0]*b[1]-b[0]*a[1];
12185 
12186  if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) {
12187  elem[iElem]->Change_Orientation();
12188  quad_flip++;
12189  }
12190  }
12191 
12192  /*--- 3D grid, tetrahedron case ---*/
12193 
12194  if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) {
12195 
12196  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12197  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12198  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12199  Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord();
12200 
12201  for (iDim = 0; iDim < nDim; iDim++) {
12202  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12203  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12204  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12205  n[0] = a[1]*b[2]-b[1]*a[2];
12206  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12207  n[2] = a[0]*b[1]-b[0]*a[1];
12208 
12209  test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12210  if (test < 0.0) {
12211  elem[iElem]->Change_Orientation();
12212  tet_flip++;
12213  }
12214 
12215  }
12216 
12217  /*--- 3D grid, prism case ---*/
12218 
12219  if (elem[iElem]->GetVTK_Type() == PRISM) {
12220 
12221  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12222  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12223  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12224  Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord();
12225  Point_5 = elem[iElem]->GetNode(4); Coord_5 = node[Point_5]->GetCoord();
12226  Point_6 = elem[iElem]->GetNode(5); Coord_6 = node[Point_6]->GetCoord();
12227 
12228  for (iDim = 0; iDim < nDim; iDim++) {
12229  a[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12230  b[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12231  c[iDim] = (Coord_4[iDim]-Coord_1[iDim])+
12232  (Coord_5[iDim]-Coord_2[iDim])+
12233  (Coord_6[iDim]-Coord_3[iDim]); }
12234 
12235  /*--- The normal vector should point to the interior of the element ---*/
12236 
12237  n[0] = a[1]*b[2]-b[1]*a[2];
12238  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12239  n[2] = a[0]*b[1]-b[0]*a[1];
12240 
12241  test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12242 
12243  for (iDim = 0; iDim < nDim; iDim++) {
12244  a[iDim] = 0.5*(Coord_5[iDim]-Coord_4[iDim]);
12245  b[iDim] = 0.5*(Coord_6[iDim]-Coord_4[iDim]);
12246  c[iDim] = (Coord_1[iDim]-Coord_4[iDim])+
12247  (Coord_2[iDim]-Coord_5[iDim])+
12248  (Coord_3[iDim]-Coord_6[iDim]); }
12249 
12250  /*--- The normal vector should point to the interior of the element ---*/
12251 
12252  n[0] = a[1]*b[2]-b[1]*a[2];
12253  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12254  n[2] = a[0]*b[1]-b[0]*a[1];
12255 
12256  test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12257 
12258  if ((test_1 < 0.0) || (test_2 < 0.0)) {
12259  elem[iElem]->Change_Orientation();
12260  prism_flip++;
12261  }
12262 
12263  }
12264 
12265  if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) {
12266 
12267  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12268  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12269  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12270  Point_4 = elem[iElem]->GetNode(5); Coord_4 = node[Point_4]->GetCoord();
12271 
12272  for (iDim = 0; iDim < nDim; iDim++) {
12273  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12274  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12275  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12276  n[0] = a[1]*b[2]-b[1]*a[2];
12277  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12278  n[2] = a[0]*b[1]-b[0]*a[1];
12279 
12280  test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12281 
12282  Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord();
12283  Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord();
12284  Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord();
12285  Point_4 = elem[iElem]->GetNode(7); Coord_4 = node[Point_4]->GetCoord();
12286 
12287  for (iDim = 0; iDim < nDim; iDim++) {
12288  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12289  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12290  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12291  n[0] = a[1]*b[2]-b[1]*a[2];
12292  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12293  n[2] = a[0]*b[1]-b[0]*a[1];
12294 
12295  test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12296 
12297  Point_1 = elem[iElem]->GetNode(1); Coord_1 = node[Point_1]->GetCoord();
12298  Point_2 = elem[iElem]->GetNode(2); Coord_2 = node[Point_2]->GetCoord();
12299  Point_3 = elem[iElem]->GetNode(3); Coord_3 = node[Point_3]->GetCoord();
12300  Point_4 = elem[iElem]->GetNode(6); Coord_4 = node[Point_4]->GetCoord();
12301 
12302  for (iDim = 0; iDim < nDim; iDim++) {
12303  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12304  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12305  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12306  n[0] = a[1]*b[2]-b[1]*a[2];
12307  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12308  n[2] = a[0]*b[1]-b[0]*a[1];
12309 
12310  test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12311 
12312  Point_1 = elem[iElem]->GetNode(3); Coord_1 = node[Point_1]->GetCoord();
12313  Point_2 = elem[iElem]->GetNode(0); Coord_2 = node[Point_2]->GetCoord();
12314  Point_3 = elem[iElem]->GetNode(1); Coord_3 = node[Point_3]->GetCoord();
12315  Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord();
12316 
12317  for (iDim = 0; iDim < nDim; iDim++) {
12318  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12319  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12320  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12321  n[0] = a[1]*b[2]-b[1]*a[2];
12322  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12323  n[2] = a[0]*b[1]-b[0]*a[1];
12324 
12325  test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12326 
12327  if ((test_1 < 0.0) || (test_2 < 0.0) || (test_3 < 0.0)
12328  || (test_4 < 0.0)) {
12329  elem[iElem]->Change_Orientation();
12330  hexa_flip++;
12331  }
12332 
12333  }
12334 
12335  if (elem[iElem]->GetVTK_Type() == PYRAMID) {
12336 
12337  Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord();
12338  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
12339  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
12340  Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord();
12341 
12342  for (iDim = 0; iDim < nDim; iDim++) {
12343  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12344  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12345  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12346  n[0] = a[1]*b[2]-b[1]*a[2];
12347  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12348  n[2] = a[0]*b[1]-b[0]*a[1];
12349 
12350  test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12351 
12352  Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord();
12353  Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord();
12354  Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord();
12355  Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord();
12356 
12357  for (iDim = 0; iDim < nDim; iDim++) {
12358  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12359  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12360  c[iDim] = Coord_4[iDim]-Coord_1[iDim]; }
12361  n[0] = a[1]*b[2]-b[1]*a[2];
12362  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12363  n[2] = a[0]*b[1]-b[0]*a[1];
12364 
12365  test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12366 
12367  if ((test_1 < 0.0) || (test_2 < 0.0)) {
12368  elem[iElem]->Change_Orientation();
12369  pyram_flip++;
12370  }
12371 
12372  }
12373 
12374  }
12375 
12376 #ifdef HAVE_MPI
12377  unsigned long Mytriangle_flip = triangle_flip;
12378  unsigned long Myquad_flip = quad_flip;
12379  unsigned long Mytet_flip = tet_flip;
12380  unsigned long Myprism_flip = prism_flip;
12381  unsigned long Myhexa_flip = hexa_flip;
12382  unsigned long Mypyram_flip = pyram_flip;
12383 
12384  SU2_MPI::Allreduce(&Mytriangle_flip, &triangle_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12385  SU2_MPI::Allreduce(&Myquad_flip, &quad_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12386  SU2_MPI::Allreduce(&Mytet_flip, &tet_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12387  SU2_MPI::Allreduce(&Myprism_flip, &prism_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12388  SU2_MPI::Allreduce(&Myhexa_flip, &hexa_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12389  SU2_MPI::Allreduce(&Mypyram_flip, &pyram_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12390 #endif
12391 
12392  if (rank == MASTER_NODE) {
12393  if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE volume elements." << endl;
12394  if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL volume elements." << endl;
12395  if (tet_flip > 0) cout << "There has been a re-orientation of the TETRAHEDRON volume elements." << endl;
12396  if (prism_flip > 0) cout << "There has been a re-orientation of the PRISM volume elements." << endl;
12397  if (hexa_flip > 0) cout << "There has been a re-orientation of the HEXAHEDRON volume elements." << endl;
12398  if (pyram_flip > 0) cout << "There has been a re-orientation of the PYRAMID volume elements." << endl;
12399  }
12400 
12401 }
12402 
12404 
12405  unsigned long Point_1_Surface, Point_2_Surface, Point_3_Surface, Point_4_Surface,
12406  iElem_Domain, Point_Domain = 0, Point_Surface, iElem_Surface,
12407  line_flip = 0, triangle_flip = 0, quad_flip = 0;
12408  su2double test_1, test_2, test_3, test_4, *Coord_1, *Coord_2, *Coord_3, *Coord_4,
12409  *Coord_5, a[3] = {0.0,0.0,0.0}, b[3] = {0.0,0.0,0.0}, c[3] = {0.0,0.0,0.0}, n[3] = {0.0,0.0,0.0}, test;
12410  unsigned short iDim, iMarker, iNode_Domain, iNode_Surface;
12411  bool find;
12412 
12413  for (iMarker = 0; iMarker < nMarker; iMarker++) {
12414 
12415  if (config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY) {
12416 
12417  for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) {
12418 
12419  iElem_Domain = bound[iMarker][iElem_Surface]->GetDomainElement();
12420  for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) {
12421  Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain);
12422  find = false;
12423  for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) {
12424  Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface);
12425  if (Point_Surface == Point_Domain) {find = true; break;}
12426  }
12427  if (!find) break;
12428  }
12429 
12430  /*--- 2D grid, line case ---*/
12431 
12432  if (bound[iMarker][iElem_Surface]->GetVTK_Type() == LINE) {
12433 
12434  Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord();
12435  Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord();
12436  Coord_3 = node[Point_Domain]->GetCoord();
12437 
12438  for (iDim = 0; iDim < nDim; iDim++) {
12439  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12440  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12441  }
12442  test = a[0]*b[1]-b[0]*a[1];
12443 
12444  if (test < 0.0) {
12445  bound[iMarker][iElem_Surface]->Change_Orientation();
12446  node[Point_1_Surface]->SetFlip_Orientation();
12447  node[Point_2_Surface]->SetFlip_Orientation();
12448  line_flip++;
12449  }
12450 
12451  }
12452 
12453  /*--- 3D grid, triangle case ---*/
12454 
12455  if (bound[iMarker][iElem_Surface]->GetVTK_Type() == TRIANGLE) {
12456 
12457  Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord();
12458  Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord();
12459  Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord();
12460  Coord_4 = node[Point_Domain]->GetCoord();
12461 
12462  for (iDim = 0; iDim < nDim; iDim++) {
12463  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12464  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12465  c[iDim] = Coord_4[iDim]-Coord_1[iDim];
12466  }
12467  n[0] = a[1]*b[2]-b[1]*a[2];
12468  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12469  n[2] = a[0]*b[1]-b[0]*a[1];
12470 
12471  test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12472  if (test < 0.0) {
12473  bound[iMarker][iElem_Surface]->Change_Orientation();
12474  node[Point_1_Surface]->SetFlip_Orientation();
12475  node[Point_2_Surface]->SetFlip_Orientation();
12476  node[Point_3_Surface]->SetFlip_Orientation();
12477  triangle_flip++;
12478  }
12479 
12480  }
12481 
12482  /*--- 3D grid, rectangle case ---*/
12483 
12484  if (bound[iMarker][iElem_Surface]->GetVTK_Type() == QUADRILATERAL) {
12485 
12486  Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord();
12487  Point_2_Surface = bound[iMarker][iElem_Surface]->GetNode(1); Coord_2 = node[Point_2_Surface]->GetCoord();
12488  Point_3_Surface = bound[iMarker][iElem_Surface]->GetNode(2); Coord_3 = node[Point_3_Surface]->GetCoord();
12489  Point_4_Surface = bound[iMarker][iElem_Surface]->GetNode(3); Coord_4 = node[Point_4_Surface]->GetCoord();
12490  Coord_5 = node[Point_Domain]->GetCoord();
12491 
12492  for (iDim = 0; iDim < nDim; iDim++) {
12493  a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]);
12494  b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]);
12495  c[iDim] = Coord_5[iDim]-Coord_1[iDim];
12496  }
12497  n[0] = a[1]*b[2]-b[1]*a[2];
12498  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12499  n[2] = a[0]*b[1]-b[0]*a[1];
12500  test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12501 
12502  for (iDim = 0; iDim < nDim; iDim++) {
12503  a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]);
12504  b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]);
12505  c[iDim] = Coord_5[iDim]-Coord_2[iDim];
12506  }
12507  n[0] = a[1]*b[2]-b[1]*a[2];
12508  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12509  n[2] = a[0]*b[1]-b[0]*a[1];
12510  test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12511 
12512  for (iDim = 0; iDim < nDim; iDim++) {
12513  a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]);
12514  b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]);
12515  c[iDim] = Coord_5[iDim]-Coord_3[iDim];
12516  }
12517  n[0] = a[1]*b[2]-b[1]*a[2];
12518  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12519  n[2] = a[0]*b[1]-b[0]*a[1];
12520  test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12521 
12522  for (iDim = 0; iDim < nDim; iDim++) {
12523  a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]);
12524  b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]);
12525  c[iDim] = Coord_5[iDim]-Coord_4[iDim];
12526  }
12527  n[0] = a[1]*b[2]-b[1]*a[2];
12528  n[1] = -(a[0]*b[2]-b[0]*a[2]);
12529  n[2] = a[0]*b[1]-b[0]*a[1];
12530  test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2];
12531 
12532  if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) {
12533  bound[iMarker][iElem_Surface]->Change_Orientation();
12534  node[Point_1_Surface]->SetFlip_Orientation();
12535  node[Point_2_Surface]->SetFlip_Orientation();
12536  node[Point_3_Surface]->SetFlip_Orientation();
12537  node[Point_4_Surface]->SetFlip_Orientation();
12538  quad_flip++;
12539  }
12540 
12541  }
12542  }
12543  }
12544  }
12545 
12546 #ifdef HAVE_MPI
12547  unsigned long Myline_flip = line_flip;
12548  unsigned long Mytriangle_flip = triangle_flip;
12549  unsigned long Myquad_flip = quad_flip;
12550  SU2_MPI::Allreduce(&Myline_flip, &line_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12551  SU2_MPI::Allreduce(&Mytriangle_flip, &triangle_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12552  SU2_MPI::Allreduce(&Myquad_flip, &quad_flip, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
12553 #endif
12554 
12555  if (rank == MASTER_NODE) {
12556  if (line_flip > 0) cout << "There has been a re-orientation of the LINE surface elements." << endl;
12557  if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE surface elements." << endl;
12558  if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL surface elements." << endl;
12559  }
12560 
12561 }
12562 
12564 
12565  /*--------------------------------------------------------------------------*/
12566  /*--- Step 1: Create the coordinates and connectivity of the linear ---*/
12567  /*--- subelements of the local boundaries that must be taken ---*/
12568  /*--- into account in the wall distance computation. ---*/
12569  /*--------------------------------------------------------------------------*/
12570 
12571  /* Initialize an array for the mesh points, which eventually contains the
12572  mapping from the local nodes to the number used in the connectivity of the
12573  local boundary faces. However, in a first pass it is an indicator whether
12574  or not a mesh point is on a local wall boundary. */
12575  vector<unsigned long> meshToSurface(nPoint, 0);
12576 
12577  /* Define the vectors for the connectivity of the local linear subelements,
12578  the element ID's, the element type and marker ID's. */
12579  vector<unsigned long> surfaceConn;
12580  vector<unsigned long> elemIDs;
12581  vector<unsigned short> VTK_TypeElem;
12582  vector<unsigned short> markerIDs;
12583 
12584  /* Loop over the boundary markers. */
12585 
12586  for(unsigned short iMarker=0; iMarker<config->GetnMarker_All(); ++iMarker) {
12587 
12588 
12589  /* Check for a viscous wall. */
12590  if( (config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) ||
12591  (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ||
12592  (config->GetMarker_All_KindBC(iMarker) == CHT_WALL_INTERFACE) ||
12593  (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION)) {
12594 
12595  /* Loop over the surface elements of this marker. */
12596  for(unsigned long iElem=0; iElem < nElem_Bound[iMarker]; iElem++) {
12597 
12598  /* Set the flag of the mesh points on this surface to true. */
12599  for (unsigned short iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
12600  unsigned long iPoint = bound[iMarker][iElem]->GetNode(iNode);
12601  meshToSurface[iPoint] = 1;
12602  }
12603  /* Determine the necessary data from the corresponding standard face,
12604  such as the number of linear subfaces, the number of DOFs per
12605  linear subface and the corresponding local connectivity. */
12606  const unsigned short VTK_Type = bound[iMarker][iElem]->GetVTK_Type();
12607  const unsigned short nDOFsPerElem = bound[iMarker][iElem]->GetnNodes();
12608 
12609  /* Loop over the nodes of element and store the required data. */
12610 
12611  markerIDs.push_back(iMarker);
12612  VTK_TypeElem.push_back(VTK_Type);
12613  elemIDs.push_back(iElem);
12614 
12615  for (unsigned short iNode = 0; iNode < nDOFsPerElem; iNode++)
12616  surfaceConn.push_back(bound[iMarker][iElem]->GetNode(iNode));
12617  }
12618  }
12619  }
12620 
12621 
12622  /*--- Create the coordinates of the local points on the viscous surfaces and
12623  create the final version of the mapping from all volume points to the
12624  points on the viscous surfaces. ---*/
12625  vector<su2double> surfaceCoor;
12626  unsigned long nVertex_SolidWall = 0;
12627 
12628  for(unsigned long i=0; i<nPoint; ++i) {
12629  if( meshToSurface[i] ) {
12630  meshToSurface[i] = nVertex_SolidWall++;
12631 
12632  for(unsigned short k=0; k<nDim; ++k)
12633  surfaceCoor.push_back(node[i]->GetCoord(k));
12634  }
12635  }
12636 
12637  /*--- Change the surface connectivity, such that it corresponds to
12638  the entries in surfaceCoor rather than in meshPoints. ---*/
12639  for(unsigned long i=0; i<surfaceConn.size(); ++i)
12640  surfaceConn[i] = meshToSurface[surfaceConn[i]];
12641 
12642  /*--------------------------------------------------------------------------*/
12643  /*--- Step 2: Build the ADT, which is an ADT of bounding boxes of the ---*/
12644  /*--- surface elements. A nearest point search does not give ---*/
12645  /*--- accurate results, especially not for the integration ---*/
12646  /*--- points of the elements close to a wall boundary. ---*/
12647  /*--------------------------------------------------------------------------*/
12648 
12649  /* Build the ADT. */
12650  CADTElemClass WallADT(nDim, surfaceCoor, surfaceConn, VTK_TypeElem,
12651  markerIDs, elemIDs, true);
12652 
12653  /* Release the memory of the vectors used to build the ADT. To make sure
12654  that all the memory is deleted, the swap function is used. */
12655  vector<unsigned short>().swap(markerIDs);
12656  vector<unsigned short>().swap(VTK_TypeElem);
12657  vector<unsigned long>().swap(elemIDs);
12658  vector<unsigned long>().swap(surfaceConn);
12659  vector<su2double>().swap(surfaceCoor);
12660 
12661  /*--------------------------------------------------------------------------*/
12662  /*--- Step 3: Loop over all interior mesh nodes and compute minimum ---*/
12663  /*--- distance to a solid wall element ---*/
12664  /*--------------------------------------------------------------------------*/
12665 
12666 
12667  if ( WallADT.IsEmpty() ) {
12668 
12669  /*--- No solid wall boundary nodes in the entire mesh.
12670  Set the wall distance to zero for all nodes. ---*/
12671 
12672  for (unsigned long iPoint=0; iPoint<GetnPoint(); ++iPoint)
12673  node[iPoint]->SetWall_Distance(0.0);
12674  }
12675  else {
12676 
12677  /*--- Solid wall boundary nodes are present. Compute the wall
12678  distance for all nodes. ---*/
12679 
12680  for (unsigned long iPoint=0; iPoint<GetnPoint(); ++iPoint) {
12681  unsigned short markerID;
12682  unsigned long elemID;
12683  int rankID;
12684  su2double dist;
12685 
12686  WallADT.DetermineNearestElement(node[iPoint]->GetCoord(), dist, markerID,
12687  elemID, rankID);
12688  node[iPoint]->SetWall_Distance(dist);
12689  }
12690  }
12691 
12692 }
12693 
12695  unsigned short iMarker, Boundary, Monitoring;
12696  unsigned long iVertex, iPoint;
12697  su2double *Normal, PositiveXArea, PositiveYArea, PositiveZArea, WettedArea, CoordX = 0.0, CoordY = 0.0, CoordZ = 0.0, MinCoordX = 1E10, MinCoordY = 1E10,
12698  MinCoordZ = 1E10, MaxCoordX = -1E10, MaxCoordY = -1E10, MaxCoordZ = -1E10, TotalMinCoordX = 1E10, TotalMinCoordY = 1E10,
12699  TotalMinCoordZ = 1E10, TotalMaxCoordX = -1E10, TotalMaxCoordY = -1E10, TotalMaxCoordZ = -1E10;
12700  su2double TotalPositiveXArea = 0.0, TotalPositiveYArea = 0.0, TotalPositiveZArea = 0.0, TotalWettedArea = 0.0, AxiFactor;
12701 
12702  bool axisymmetric = config->GetAxisymmetric();
12703  bool fea = ((config->GetKind_Solver() == FEM_ELASTICITY) || (config->GetKind_Solver() == DISC_ADJ_FEM));
12704 
12705  PositiveXArea = 0.0;
12706  PositiveYArea = 0.0;
12707  PositiveZArea = 0.0;
12708  WettedArea = 0.0;
12709 
12710  for (iMarker = 0; iMarker < nMarker; iMarker++) {
12711  Boundary = config->GetMarker_All_KindBC(iMarker);
12712  Monitoring = config->GetMarker_All_Monitoring(iMarker);
12713 
12714  if ((((Boundary == EULER_WALL) ||
12715  (Boundary == HEAT_FLUX) ||
12716  (Boundary == ISOTHERMAL) ||
12717  (Boundary == LOAD_BOUNDARY) ||
12718  (Boundary == DISPLACEMENT_BOUNDARY) ||
12719  (Boundary == TRANSPIRATION)) && (Monitoring == YES))
12720  || (fea))
12721 
12722  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
12723  iPoint = vertex[iMarker][iVertex]->GetNode();
12724 
12725  if (node[iPoint]->GetDomain()) {
12726  Normal = vertex[iMarker][iVertex]->GetNormal();
12727  CoordX = node[iPoint]->GetCoord(0);
12728  CoordY = node[iPoint]->GetCoord(1);
12729  if (nDim == 3) CoordZ = node[iPoint]->GetCoord(2);
12730 
12731  if (axisymmetric) AxiFactor = 2.0*PI_NUMBER*node[iPoint]->GetCoord(1);
12732  else AxiFactor = 1.0;
12733 
12734  if (nDim == 2) WettedArea += AxiFactor * sqrt (Normal[0]*Normal[0] + Normal[1]*Normal[1]);
12735  if (nDim == 3) WettedArea += sqrt (Normal[0]*Normal[0] + Normal[1]*Normal[1] + Normal[2]*Normal[2]);
12736 
12737  if (Normal[0] < 0) PositiveXArea -= Normal[0];
12738  if (Normal[1] < 0) PositiveYArea -= Normal[1];
12739  if ((nDim == 3) && (Normal[2] < 0)) PositiveZArea -= Normal[2];
12740 
12741  if (CoordX < MinCoordX) MinCoordX = CoordX;
12742  if (CoordX > MaxCoordX) MaxCoordX = CoordX;
12743 
12744  if (CoordY < MinCoordY) MinCoordY = CoordY;
12745  if (CoordY > MaxCoordY) MaxCoordY = CoordY;
12746 
12747  if (nDim == 3) {
12748  if (CoordZ < MinCoordZ) MinCoordZ = CoordZ;
12749  if (CoordZ > MaxCoordZ) MaxCoordZ = CoordZ;
12750  }
12751 
12752  }
12753  }
12754 
12755  }
12756 
12757 #ifdef HAVE_MPI
12758  SU2_MPI::Allreduce(&PositiveXArea, &TotalPositiveXArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
12759  SU2_MPI::Allreduce(&PositiveYArea, &TotalPositiveYArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
12760  SU2_MPI::Allreduce(&PositiveZArea, &TotalPositiveZArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
12761 
12762  SU2_MPI::Allreduce(&MinCoordX, &TotalMinCoordX, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
12763  SU2_MPI::Allreduce(&MinCoordY, &TotalMinCoordY, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
12764  SU2_MPI::Allreduce(&MinCoordZ, &TotalMinCoordZ, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
12765 
12766  SU2_MPI::Allreduce(&MaxCoordX, &TotalMaxCoordX, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
12767  SU2_MPI::Allreduce(&MaxCoordY, &TotalMaxCoordY, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
12768  SU2_MPI::Allreduce(&MaxCoordZ, &TotalMaxCoordZ, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
12769 
12770  SU2_MPI::Allreduce(&WettedArea, &TotalWettedArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
12771 #else
12772  TotalPositiveXArea = PositiveXArea;
12773  TotalPositiveYArea = PositiveYArea;
12774  TotalPositiveZArea = PositiveZArea;
12775 
12776  TotalMinCoordX = MinCoordX;
12777  TotalMinCoordY = MinCoordY;
12778  TotalMinCoordZ = MinCoordZ;
12779 
12780  TotalMaxCoordX = MaxCoordX;
12781  TotalMaxCoordY = MaxCoordY;
12782  TotalMaxCoordZ = MaxCoordZ;
12783 
12784  TotalWettedArea = WettedArea;
12785 #endif
12786 
12787  /*--- Set a reference area if no value is provided ---*/
12788 
12789  if (config->GetRefArea() == 0.0) {
12790 
12791  if (nDim == 3) config->SetRefArea(TotalPositiveZArea);
12792  else config->SetRefArea(TotalPositiveYArea);
12793 
12794  if (rank == MASTER_NODE) {
12795  if (nDim == 3) {
12796  cout << "Reference area = "<< TotalPositiveZArea;
12797  if (config->GetSystemMeasurements() == SI) cout <<" m^2." << endl; else cout <<" ft^2." << endl;
12798  }
12799  else {
12800  cout << "Reference length = "<< TotalPositiveYArea;
12801  if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl;
12802  }
12803  }
12804 
12805  }
12806 
12807  /*--- Set a semi-span value if no value is provided ---*/
12808 
12809  if (config->GetSemiSpan() == 0.0) {
12810 
12811  if (nDim == 3) config->SetSemiSpan(fabs(TotalMaxCoordY));
12812  else config->SetSemiSpan(1.0);
12813 
12814  if ((nDim == 3) && (rank == MASTER_NODE)) {
12815  cout << "Semi-span length = "<< TotalMaxCoordY;
12816  if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl;
12817  }
12818 
12819  }
12820 
12821  if (rank == MASTER_NODE) {
12822 
12823  if (fea) cout << "Surface area = "<< TotalWettedArea;
12824  else cout << "Wetted area = "<< TotalWettedArea;
12825 
12826  if ((nDim == 3) || (axisymmetric)) { if (config->GetSystemMeasurements() == SI) cout <<" m^2." << endl; else cout <<" ft^2." << endl; }
12827  else { if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl; }
12828 
12829  cout << "Area projection in the x-plane = "<< TotalPositiveXArea;
12830  if (nDim == 3) { if (config->GetSystemMeasurements() == SI) cout <<" m^2,"; else cout <<" ft^2,"; }
12831  else { if (config->GetSystemMeasurements() == SI) cout <<" m,"; else cout <<" ft,"; }
12832 
12833  cout << " y-plane = "<< TotalPositiveYArea;
12834  if (nDim == 3) { if (config->GetSystemMeasurements() == SI) cout <<" m^2,"; else cout <<" ft^2,"; }
12835  else { if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl; }
12836 
12837  if (nDim == 3) { cout << " z-plane = "<< TotalPositiveZArea;
12838  if (config->GetSystemMeasurements() == SI) cout <<" m^2." << endl; else cout <<" ft^2."<< endl; }
12839 
12840  cout << "Max. coordinate in the x-direction = "<< TotalMaxCoordX;
12841  if (config->GetSystemMeasurements() == SI) cout <<" m,"; else cout <<" ft,";
12842 
12843  cout << " y-direction = "<< TotalMaxCoordY;
12844  if (config->GetSystemMeasurements() == SI) cout <<" m"; else cout <<" ft";
12845 
12846  if (nDim == 3) {
12847  cout << ", z-direction = "<< TotalMaxCoordZ;
12848  if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft."<< endl;
12849  }
12850  else cout << "." << endl;
12851 
12852  cout << "Min coordinate in the x-direction = "<< TotalMinCoordX;
12853  if (config->GetSystemMeasurements() == SI) cout <<" m,"; else cout <<" ft";
12854 
12855  cout << " y-direction = "<< TotalMinCoordY;
12856  if (config->GetSystemMeasurements() == SI) cout <<" m"; else cout <<" ft";
12857 
12858  if (nDim == 3) {
12859  cout << ", z-direction = "<< TotalMinCoordZ;
12860  if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft."<< endl;
12861  }
12862  else cout << "." << endl;
12863 
12864  }
12865 
12866 }
12867 
12869 
12870  unsigned short Node_Neighbor, iNode, iNeighbor;
12871  unsigned long jElem, Point_Neighbor, iPoint, iElem;
12872 
12873  /*--- Loop over all the elements ---*/
12874 
12875  for (iElem = 0; iElem < nElem; iElem++)
12876 
12877  /*--- Loop over all the nodes of an element ---*/
12878 
12879  for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) {
12880  iPoint = elem[iElem]->GetNode(iNode);
12881 
12882  /*--- Store the element into the point ---*/
12883 
12884  node[iPoint]->SetElem(iElem);
12885  }
12886 
12887  /*--- Loop over all the points ---*/
12888 
12889  for (iPoint = 0; iPoint < nPoint; iPoint++)
12890 
12891  /*--- Loop over all elements shared by the point ---*/
12892 
12893  for (iElem = 0; iElem < node[iPoint]->GetnElem(); iElem++) {
12894 
12895  jElem = node[iPoint]->GetElem(iElem);
12896 
12897  /*--- If we find the point iPoint in the surronding element ---*/
12898 
12899  for (iNode = 0; iNode < elem[jElem]->GetnNodes(); iNode++)
12900 
12901  if (elem[jElem]->GetNode(iNode) == iPoint)
12902 
12903  /*--- Localize the local index of the neighbor of iPoint in the element ---*/
12904 
12905  for (iNeighbor = 0; iNeighbor < elem[jElem]->GetnNeighbor_Nodes(iNode); iNeighbor++) {
12906  Node_Neighbor = elem[jElem]->GetNeighbor_Nodes(iNode, iNeighbor);
12907  Point_Neighbor = elem[jElem]->GetNode(Node_Neighbor);
12908 
12909  /*--- Store the point into the point ---*/
12910 
12911  node[iPoint]->SetPoint(Point_Neighbor);
12912  }
12913  }
12914 
12915  /*--- Set the number of neighbors variable, this is
12916  important for JST and multigrid in parallel ---*/
12917 
12918  for (iPoint = 0; iPoint < nPoint; iPoint++)
12919  node[iPoint]->SetnNeighbor(node[iPoint]->GetnPoint());
12920 
12921 }
12922 
12924  unsigned long iPoint, AdjPoint, AuxPoint, AddPoint, iElem, iNode, jNode;
12925  vector<unsigned long> Queue, AuxQueue, Result;
12926  unsigned short Degree, MinDegree, iDim, iMarker;
12927  bool *inQueue;
12928 
12929  inQueue = new bool [nPoint];
12930 
12931  for (iPoint = 0; iPoint < nPoint; iPoint++)
12932  inQueue[iPoint] = false;
12933 
12934  /*--- Select the node with the lowest degree in the grid. ---*/
12935 
12936  MinDegree = node[0]->GetnNeighbor(); AddPoint = 0;
12937  for (iPoint = 1; iPoint < nPointDomain; iPoint++) {
12938  Degree = node[iPoint]->GetnPoint();
12939  if (Degree < MinDegree) { MinDegree = Degree; AddPoint = iPoint; }
12940  }
12941 
12942  /*--- Add the node in the first free position. ---*/
12943 
12944  Result.push_back(AddPoint); inQueue[AddPoint] = true;
12945 
12946  /*--- Loop until reorganize all the nodes ---*/
12947 
12948  do {
12949 
12950  /*--- Add to the queue all the nodes adjacent in the increasing
12951  order of their degree, checking if the element is already
12952  in the Queue. ---*/
12953 
12954  AuxQueue.clear();
12955  for (iNode = 0; iNode < node[AddPoint]->GetnPoint(); iNode++) {
12956  AdjPoint = node[AddPoint]->GetPoint(iNode);
12957  if ((!inQueue[AdjPoint]) && (AdjPoint < nPointDomain)) {
12958  AuxQueue.push_back(AdjPoint);
12959  }
12960  }
12961 
12962  if (AuxQueue.size() != 0) {
12963 
12964  /*--- Sort the auxiliar queue based on the number of neighbors ---*/
12965 
12966  for (iNode = 0; iNode < AuxQueue.size(); iNode++) {
12967  for (jNode = 0; jNode < AuxQueue.size() - 1 - iNode; jNode++) {
12968  if (node[AuxQueue[jNode]]->GetnPoint() > node[AuxQueue[jNode+1]]->GetnPoint()) {
12969  AuxPoint = AuxQueue[jNode];
12970  AuxQueue[jNode] = AuxQueue[jNode+1];
12971  AuxQueue[jNode+1] = AuxPoint;
12972  }
12973  }
12974  }
12975 
12976  Queue.insert(Queue.end(), AuxQueue.begin(), AuxQueue.end());
12977  for (iNode = 0; iNode < AuxQueue.size(); iNode++) {
12978  inQueue[AuxQueue[iNode]] = true;
12979  }
12980 
12981  }
12982 
12983  /*--- Extract the first node from the queue and add it in the first free
12984  position. ---*/
12985 
12986  if (Queue.size() != 0) {
12987  AddPoint = Queue[0];
12988  Result.push_back(Queue[0]);
12989  Queue.erase (Queue.begin(), Queue.begin()+1);
12990  }
12991 
12992  /*--- Add to the queue all the nodes adjacent in the increasing
12993  order of their degree, checking if the element is already
12994  in the Queue. ---*/
12995 
12996  } while (Queue.size() != 0);
12997 
12998  /*--- Check that all the points have been added ---*/
12999 
13000  for (iPoint = 0; iPoint < nPointDomain; iPoint++) {
13001  if (inQueue[iPoint] == false) Result.push_back(iPoint);
13002  }
13003 
13004  delete[] inQueue;
13005 
13006  reverse(Result.begin(), Result.end());
13007 
13008  /*--- Add the MPI points ---*/
13009 
13010  for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) {
13011  Result.push_back(iPoint);
13012  }
13013 
13014  /*--- Reset old data structures ---*/
13015 
13016  for (iPoint = 0; iPoint < nPoint; iPoint++) {
13017  node[iPoint]->ResetElem();
13018  node[iPoint]->ResetPoint();
13019  node[iPoint]->ResetBoundary();
13020  node[iPoint]->SetPhysicalBoundary(false);
13021  node[iPoint]->SetSolidBoundary(false);
13022  node[iPoint]->SetDomain(true);
13023  }
13024 
13025  /*--- Set the new coordinates ---*/
13026 
13027  su2double **AuxCoord;
13028  unsigned long *AuxGlobalIndex;
13029 
13030  AuxGlobalIndex = new unsigned long [nPoint];
13031  AuxCoord = new su2double* [nPoint];
13032  for (iPoint = 0; iPoint < nPoint; iPoint++)
13033  AuxCoord[iPoint] = new su2double [nDim];
13034 
13035  for (iPoint = 0; iPoint < nPoint; iPoint++) {
13036  AuxGlobalIndex[iPoint] = node[iPoint]->GetGlobalIndex();
13037  for (iDim = 0; iDim < nDim; iDim++) {
13038  AuxCoord[iPoint][iDim] = node[iPoint]->GetCoord(iDim);
13039  }
13040  }
13041 
13042  for (iPoint = 0; iPoint < nPoint; iPoint++) {
13043  node[iPoint]->SetGlobalIndex(AuxGlobalIndex[Result[iPoint]]);
13044  for (iDim = 0; iDim < nDim; iDim++)
13045  node[iPoint]->SetCoord(iDim, AuxCoord[Result[iPoint]][iDim]);
13046  }
13047 
13048  for (iPoint = 0; iPoint < nPoint; iPoint++)
13049  delete[] AuxCoord[iPoint];
13050  delete[] AuxCoord;
13051  delete[] AuxGlobalIndex;
13052 
13053  /*--- Set the new conectivities ---*/
13054 
13055  unsigned long *InvResult;
13056  InvResult = new unsigned long [nPoint];
13057  for (iPoint = 0; iPoint < nPoint; iPoint++)
13058  InvResult[Result[iPoint]] = iPoint;
13059 
13060  for (iElem = 0; iElem < nElem; iElem++) {
13061  for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) {
13062  iPoint = elem[iElem]->GetNode(iNode);
13063  elem[iElem]->SetNode(iNode, InvResult[iPoint]);
13064  }
13065  }
13066 
13067  for (iMarker = 0; iMarker < nMarker; iMarker++) {
13068  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) {
13069 
13070  string Marker_Tag = config->GetMarker_All_TagBound(iMarker);
13071  if (Marker_Tag == "SEND_RECEIVE") {
13072  for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
13073  if (config->GetMarker_All_SendRecv(iMarker) < 0)
13074  node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false);
13075  }
13076  }
13077 
13078  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
13079  iPoint = bound[iMarker][iElem]->GetNode(iNode);
13080  bound[iMarker][iElem]->SetNode(iNode, InvResult[iPoint]);
13081  node[InvResult[iPoint]]->SetBoundary(nMarker);
13082  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE &&
13083  config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY &&
13084  config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY &&
13085  config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY &&
13086  config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY)
13087  node[InvResult[iPoint]]->SetPhysicalBoundary(true);
13088 
13089  if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL ||
13090  config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX ||
13091  config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL ||
13092  config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION)
13093  node[InvResult[iPoint]]->SetSolidBoundary(true);
13094  }
13095  }
13096  }
13097 
13098 
13099  delete[] InvResult;
13100 
13101 }
13102 
13104  unsigned short first_elem_face, second_elem_face, iFace, iNode, jElem;
13105  unsigned long face_point, Test_Elem, iElem;
13106 
13107  /*--- Loop over all the elements, faces and nodes ---*/
13108 
13109  for (iElem = 0; iElem < nElem; iElem++)
13110  for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++)
13111  for (iNode = 0; iNode < elem[iElem]->GetnNodesFace(iFace); iNode++) {
13112  face_point = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iNode));
13113 
13114  /*--- Loop over all elements sharing the face point ---*/
13115 
13116  for (jElem = 0; jElem < node[face_point]->GetnElem(); jElem++) {
13117  Test_Elem = node[face_point]->GetElem(jElem);
13118 
13119  /*--- If it is a new element in this face ---*/
13120 
13121  if ((elem[iElem]->GetNeighbor_Elements(iFace) == -1) && (iElem < Test_Elem) &&
13122  (FindFace(iElem, Test_Elem, first_elem_face, second_elem_face))) {
13123 
13124  /*--- Localice which faces are sharing both elements ---*/
13125 
13126  elem[iElem]->SetNeighbor_Elements(Test_Elem, first_elem_face);
13127 
13128  /*--- Store the element for both elements ---*/
13129 
13130  elem[Test_Elem]->SetNeighbor_Elements(iElem, second_elem_face);
13131 
13132  }
13133  }
13134  }
13135 }
13136 
13138  unsigned short cont, iMarker, iElem, iNode_Domain, iNode_Surface;
13139  unsigned long Point_Domain, Point_Surface, Point, iElem_Surface, iElem_Domain;
13140  bool CheckVol;
13141 
13142  for (iMarker = 0; iMarker < nMarker; iMarker++)
13143  for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) {
13144 
13145  /*--- Choose and arbitrary point from the surface --*/
13146  Point = bound[iMarker][iElem_Surface]->GetNode(0);
13147  CheckVol = false;
13148 
13149  for (iElem = 0; iElem < node[Point]->GetnElem(); iElem++) {
13150  /*--- Look for elements surronding that point --*/
13151  cont = 0; iElem_Domain = node[Point]->GetElem(iElem);
13152  for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) {
13153  Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain);
13154  for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) {
13155  Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface);
13156  if (Point_Surface == Point_Domain) cont++;
13157  if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break;
13158  }
13159  if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break;
13160  }
13161 
13162  if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) {
13163  bound[iMarker][iElem_Surface]->SetDomainElement(iElem_Domain);
13164  CheckVol = true;
13165  break;
13166  }
13167  }
13168  if (!CheckVol) {
13169  char buf[100];
13170  SPRINTF(buf,"The surface element (%u, %lu) doesn't have an associated volume element", iMarker, iElem_Surface );
13172  }
13173  }
13174 }
13175 
13177  unsigned long iPoint, iVertex, iElem;
13178  unsigned short iMarker, iNode;
13179 
13180  /*--- Initialize the Vertex vector for each node of the grid ---*/
13181 
13182  for (iPoint = 0; iPoint < nPoint; iPoint++)
13183  for (iMarker = 0; iMarker < nMarker; iMarker++)
13184  node[iPoint]->SetVertex(-1, iMarker);
13185 
13186  /*--- Create and compute the vector with the number of vertex per marker ---*/
13187 
13188  nVertex = new unsigned long [nMarker];
13189  for (iMarker = 0; iMarker < nMarker; iMarker++) {
13190 
13191  /*--- Initialize the number of Bound Vertex for each Marker ---*/
13192 
13193  nVertex[iMarker] = 0;
13194  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++)
13195  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
13196  iPoint = bound[iMarker][iElem]->GetNode(iNode);
13197 
13198  /*--- Set the vertex in the node information ---*/
13199 
13200  if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) {
13201  node[iPoint]->SetVertex(nVertex[iMarker], iMarker);
13202  nVertex[iMarker]++;
13203  }
13204  }
13205  }
13206 
13207  /*--- Initialize the Vertex vector for each node, the previous result is deleted ---*/
13208 
13209  for (iPoint = 0; iPoint < nPoint; iPoint++)
13210  for (iMarker = 0; iMarker < nMarker; iMarker++)
13211  node[iPoint]->SetVertex(-1, iMarker);
13212 
13213  /*--- Create the bound vertex structure, note that the order
13214  is the same as in the input file, this is important for Send/Receive part ---*/
13215 
13216  vertex = new CVertex**[nMarker];
13217  for (iMarker = 0; iMarker < nMarker; iMarker++) {
13218  vertex[iMarker] = new CVertex* [nVertex[iMarker]];
13219  nVertex[iMarker] = 0;
13220 
13221  /*--- Initialize the number of Bound Vertex for each Marker ---*/
13222 
13223  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++)
13224  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
13225  iPoint = bound[iMarker][iElem]->GetNode(iNode);
13226 
13227  /*--- Set the vertex in the node information ---*/
13228 
13229  if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) {
13230  iVertex = nVertex[iMarker];
13231  vertex[iMarker][iVertex] = new CVertex(iPoint, nDim);
13232 
13233  if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) {
13234  vertex[iMarker][iVertex]->SetRotation_Type(bound[iMarker][iElem]->GetRotation_Type());
13235  }
13236  node[iPoint]->SetVertex(nVertex[iMarker], iMarker);
13237  nVertex[iMarker]++;
13238  }
13239  }
13240  }
13241 }
13242 
13243 void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {
13244  unsigned short iMarker, jMarker, iMarkerTP, iSpan, jSpan, kSpan = 0;
13245  unsigned long iPoint, iVertex;
13246  long jVertex;
13247  int nSpan, nSpan_loc;
13248  su2double *coord, *valueSpan, min, max, radius, delta;
13249  short SendRecv;
13250  bool isPeriodic;
13251  unsigned short SpanWise_Kind = config->GetKind_SpanWise();
13252 
13253 #ifdef HAVE_MPI
13254  unsigned short iSize;
13255  int nSpan_max;
13256  int My_nSpan, My_MaxnSpan, *My_nSpan_loc = NULL;
13257  su2double MyMin, MyMax, *MyTotValueSpan =NULL,*MyValueSpan =NULL;
13258 #endif
13259 
13260  nSpan = 0;
13261  nSpan_loc = 0;
13262  if (nDim == 2){
13263  nSpanWiseSections[marker_flag-1] = 1;
13264  //TODO (turbo) make it more genral
13265  if(marker_flag == OUTFLOW) config->SetnSpanWiseSections(1);
13266 
13267  /*---Initilize the vector of span-wise values that will be ordered ---*/
13268  SpanWiseValue[marker_flag -1] = new su2double[1];
13269  for (iSpan = 0; iSpan < 1; iSpan++){
13270  SpanWiseValue[marker_flag -1][iSpan] = 0;
13271  }
13272  }
13273  else{
13274  if(SpanWise_Kind == AUTOMATIC){
13275  /*--- loop to find inflow of outflow marker---*/
13276  for (iMarker = 0; iMarker < nMarker; iMarker++){
13277  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
13278  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
13279  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
13280  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
13281  iPoint = vertex[iMarker][iVertex]->GetNode();
13282 
13283  /*--- loop to find the vertex that ar both of inflow or outflow marker and on the periodic
13284  * in order to caount the number of Span ---*/
13285  for (jMarker = 0; jMarker < nMarker; jMarker++){
13286  if (config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) {
13287  SendRecv = config->GetMarker_All_SendRecv(jMarker);
13288  jVertex = node[iPoint]->GetVertex(jMarker);
13289  if (jVertex != -1) {
13290  isPeriodic = ((vertex[jMarker][jVertex]->GetRotation_Type() > 0) && (vertex[jMarker][jVertex]->GetRotation_Type() % 2 == 1));
13291  if (isPeriodic && (SendRecv < 0)){
13292  nSpan++;
13293 
13294  }
13295  }
13296  }
13297  }
13298  }
13299  }
13300  }
13301  }
13302  }
13303 
13304  /*--- storing the local number of span---*/
13305  nSpan_loc = nSpan;
13306  /*--- if parallel computing the global number of span---*/
13307 #ifdef HAVE_MPI
13308  nSpan_max = nSpan;
13309  My_nSpan = nSpan; nSpan = 0;
13310  My_MaxnSpan = nSpan_max; nSpan_max = 0;
13311  SU2_MPI::Allreduce(&My_nSpan, &nSpan, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
13312  SU2_MPI::Allreduce(&My_MaxnSpan, &nSpan_max, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
13313 #endif
13314 
13315 
13316 
13317  /*--- initialize the vector that will contain the disordered values span-wise ---*/
13318  nSpanWiseSections[marker_flag -1] = nSpan;
13319  valueSpan = new su2double[nSpan];
13320 
13321  for (iSpan = 0; iSpan < nSpan; iSpan ++ ){
13322  valueSpan[iSpan] = -1001.0;
13323  }
13324 
13325 
13326  /*--- store the local span-wise value for each processor ---*/
13327  nSpan_loc = 0;
13328  for (iMarker = 0; iMarker < nMarker; iMarker++){
13329  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
13330  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
13331  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
13332  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
13333  iPoint = vertex[iMarker][iVertex]->GetNode();
13334  for (jMarker = 0; jMarker < nMarker; jMarker++){
13335  if (config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) {
13336  SendRecv = config->GetMarker_All_SendRecv(jMarker);
13337  jVertex = node[iPoint]->GetVertex(jMarker);
13338  if (jVertex != -1) {
13339  isPeriodic = ((vertex[jMarker][jVertex]->GetRotation_Type() > 0) && (vertex[jMarker][jVertex]->GetRotation_Type() % 2 == 1));
13340  if (isPeriodic && (SendRecv < 0)){
13341  coord = node[iPoint]->GetCoord();
13342  switch (config->GetKind_TurboMachinery(val_iZone)){
13343  case CENTRIFUGAL:
13344  valueSpan[nSpan_loc] = coord[2];
13345  break;
13346  case CENTRIPETAL:
13347  valueSpan[nSpan_loc] = coord[2];
13348  break;
13349  case AXIAL:
13350  valueSpan[nSpan_loc] = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13351  break;
13352  case CENTRIPETAL_AXIAL:
13353  if (marker_flag == OUTFLOW){
13354  valueSpan[nSpan_loc] = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13355  }
13356  else{
13357  valueSpan[nSpan_loc] = coord[2];
13358  }
13359  break;
13360  case AXIAL_CENTRIFUGAL:
13361  if (marker_flag == INFLOW){
13362  valueSpan[nSpan_loc] = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13363  }
13364  else{
13365  valueSpan[nSpan_loc] = coord[2];
13366  }
13367  break;
13368 
13369  }
13370  nSpan_loc++;
13371  }
13372  }
13373  }
13374  }
13375  }
13376  }
13377  }
13378  }
13379  }
13380 
13381  /*--- Gather the span-wise values on all the processor ---*/
13382 
13383 #ifdef HAVE_MPI
13384  MyTotValueSpan = new su2double[nSpan_max*size];
13385  MyValueSpan = new su2double[nSpan_max];
13386  My_nSpan_loc = new int[size];
13387  for(iSpan = 0; iSpan < nSpan_max; iSpan++){
13388  MyValueSpan[iSpan] = -1001.0;
13389  for (iSize = 0; iSize< size; iSize++){
13390  MyTotValueSpan[iSize*nSpan_max + iSpan] = -1001.0;
13391  }
13392  }
13393 
13394  for(iSpan = 0; iSpan <nSpan_loc; iSpan++){
13395  MyValueSpan[iSpan] = valueSpan[iSpan];
13396  }
13397 
13398  for(iSpan = 0; iSpan <nSpan; iSpan++){
13399  valueSpan[iSpan] = -1001.0;
13400  }
13401 
13402  SU2_MPI::Allgather(MyValueSpan, nSpan_max , MPI_DOUBLE, MyTotValueSpan, nSpan_max, MPI_DOUBLE, MPI_COMM_WORLD);
13403  SU2_MPI::Allgather(&nSpan_loc, 1 , MPI_INT, My_nSpan_loc, 1, MPI_INT, MPI_COMM_WORLD);
13404 
13405  jSpan = 0;
13406  for (iSize = 0; iSize< size; iSize++){
13407  for(iSpan = 0; iSpan < My_nSpan_loc[iSize]; iSpan++){
13408  valueSpan[jSpan] = MyTotValueSpan[iSize*nSpan_max + iSpan];
13409  jSpan++;
13410  }
13411  }
13412 
13413  delete [] MyTotValueSpan; delete [] MyValueSpan; delete [] My_nSpan_loc;
13414 
13415 #endif
13416 
13417  // check if the value are gathered correctly
13418  //
13419  // for (iSpan = 0; iSpan < nSpan; iSpan++){
13420  // if(rank == MASTER_NODE){
13421  // cout << setprecision(16)<< iSpan +1 << " with a value of " <<valueSpan[iSpan]<< " at flag " << marker_flag <<endl;
13422  // }
13423  // }
13424 
13425 
13426  /*--- Find the minimum value among the span-wise values ---*/
13427  min = 10.0E+06;
13428  for (iSpan = 0; iSpan < nSpan; iSpan++){
13429  if(valueSpan[iSpan]< min) min = valueSpan[iSpan];
13430  }
13431 
13432  /*---Initilize the vector of span-wise values that will be ordered ---*/
13433  SpanWiseValue[marker_flag -1] = new su2double[nSpan];
13434  for (iSpan = 0; iSpan < nSpan; iSpan++){
13435  SpanWiseValue[marker_flag -1][iSpan] = 0;
13436  }
13437 
13438  /*---Ordering the vector of span-wise values---*/
13439  SpanWiseValue[marker_flag -1][0] = min;
13440  for (iSpan = 1; iSpan < nSpan; iSpan++){
13441  min = 10.0E+06;
13442  for (jSpan = 0; jSpan < nSpan; jSpan++){
13443  if((valueSpan[jSpan] - SpanWiseValue[marker_flag -1][iSpan-1]) < min && (valueSpan[jSpan] - SpanWiseValue[marker_flag -1][iSpan-1]) > EPS){
13444  min = valueSpan[jSpan] - SpanWiseValue[marker_flag -1][iSpan-1];
13445  kSpan = jSpan;
13446  }
13447  }
13448  SpanWiseValue[marker_flag -1][iSpan] = valueSpan[kSpan];
13449  }
13450 
13451  delete [] valueSpan;
13452  }
13453  /*--- Compute equispaced Span-wise sections using number of section specified by the User---*/
13454  else{
13455  /*--- Initialize number of span---*/
13456  nSpanWiseSections[marker_flag-1] = config->Get_nSpanWiseSections_User();
13457  SpanWiseValue[marker_flag -1] = new su2double[config->Get_nSpanWiseSections_User()];
13458  for (iSpan = 0; iSpan < config->Get_nSpanWiseSections_User(); iSpan++){
13459  SpanWiseValue[marker_flag -1][iSpan] = 0;
13460  }
13461  /*--- Compute maximum and minimum value span-wise---*/
13462  min = 10.0E+06;
13463  max = -10.0E+06;
13464  for (iMarker = 0; iMarker < nMarker; iMarker++){
13465  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
13466  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
13467  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
13468  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
13469  iPoint = vertex[iMarker][iVertex]->GetNode();
13470  for (jMarker = 0; jMarker < nMarker; jMarker++){
13471  if (config->GetMarker_All_KindBC(jMarker) == SEND_RECEIVE) {
13472  SendRecv = config->GetMarker_All_SendRecv(jMarker);
13473  jVertex = node[iPoint]->GetVertex(jMarker);
13474  if (jVertex != -1) {
13475  isPeriodic = ((vertex[jMarker][jVertex]->GetRotation_Type() > 0) && (vertex[jMarker][jVertex]->GetRotation_Type() % 2 == 1));
13476  if (isPeriodic && (SendRecv < 0)){
13477  coord = node[iPoint]->GetCoord();
13478  switch (config->GetKind_TurboMachinery(val_iZone)){
13479  case CENTRIFUGAL: case CENTRIPETAL:
13480  if (coord[2] < min) min = coord[2];
13481  if (coord[2] > max) max = coord[2];
13482  break;
13483  case AXIAL:
13484  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13485  if (radius < min) min = radius;
13486  if (radius > max) max = radius;
13487  break;
13488  case CENTRIPETAL_AXIAL:
13489  if (marker_flag == OUTFLOW){
13490  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13491  if (radius < min) min = radius;
13492  if (radius > max) max = radius;
13493  }
13494  else{
13495  if (coord[2] < min) min = coord[2];
13496  if (coord[2] > max) max = coord[2];
13497  }
13498  break;
13499 
13500  case AXIAL_CENTRIFUGAL:
13501  if (marker_flag == INFLOW){
13502  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13503  if (radius < min) min = radius;
13504  if (radius > max) max = radius;
13505  }
13506  else{
13507  if (coord[2] < min) min = coord[2];
13508  if (coord[2] > max) max = coord[2];
13509  }
13510  break;
13511  }
13512 
13513  }
13514  }
13515  }
13516  }
13517  }
13518  }
13519  }
13520  }
13521  }
13522  /*--- compute global minimum and maximum value on span-wise ---*/
13523 #ifdef HAVE_MPI
13524  MyMin= min; min = 0;
13525  MyMax= max; max = 0;
13528 #endif
13529 
13530  // cout <<"min " << min << endl;
13531  // cout <<"max " << max << endl;
13532  /*--- compute height value for each spanwise section---*/
13533  delta = (max - min)/(nSpanWiseSections[marker_flag-1] -1);
13534  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13535  SpanWiseValue[marker_flag - 1][iSpan]= min + delta*iSpan;
13536  }
13537  }
13538 
13539 
13540  if(marker_flag == OUTFLOW){
13542  char buf[100];
13543  SPRINTF(buf, "nSpan inflow %u, nSpan outflow %u", nSpanWiseSections[INFLOW], nSpanWiseSections[OUTFLOW]);
13544  SU2_MPI::Error(string(" At the moment only turbomachinery with the same amount of span-wise section can be simulated\n") + buf, CURRENT_FUNCTION);
13545  }
13546  else{
13548  }
13549  }
13550 
13551 
13552 
13553  }
13554 
13555 }
13556 void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {
13557  unsigned long iPoint, **ordered, **disordered, **oldVertex3D, iInternalVertex;
13558  unsigned long nVert, nVertMax;
13559  unsigned short iMarker, iMarkerTP, iSpan, jSpan, iDim;
13560  su2double min, minInt, max, *coord, dist, Normal2, *TurboNormal, *NormalArea, target = 0.0, **area, ***unitnormal, Area = 0.0;
13561  bool **checkAssign;
13562  min = 10.0E+06;
13563  minInt = 10.0E+06;
13564  max = -10.0E+06;
13565 
13566  su2double radius;
13567  long iVertex, iSpanVertex, jSpanVertex, kSpanVertex = 0;
13568  int *nTotVertex_gb, *nVertexSpanHalo;
13569  su2double **x_loc, **y_loc, **z_loc, **angCoord_loc, **deltaAngCoord_loc, **angPitch, **deltaAngPitch, *minIntAngPitch,
13570  *minAngPitch, *maxAngPitch;
13571  int **rank_loc;
13572 #ifdef HAVE_MPI
13573  unsigned short iSize, kSize = 0, jSize;
13574  su2double MyMin,MyIntMin, MyMax;
13575  su2double *x_gb = NULL, *y_gb = NULL, *z_gb = NULL, *angCoord_gb = NULL, *deltaAngCoord_gb = NULL;
13576  bool *checkAssign_gb =NULL;
13577  unsigned long My_nVert;
13578 
13579 #endif
13580  string multizone_filename;
13581 
13582  x_loc = new su2double*[nSpanWiseSections[marker_flag-1]];
13583  y_loc = new su2double*[nSpanWiseSections[marker_flag-1]];
13584  z_loc = new su2double*[nSpanWiseSections[marker_flag-1]];
13585  angCoord_loc = new su2double*[nSpanWiseSections[marker_flag-1]];
13586  deltaAngCoord_loc = new su2double*[nSpanWiseSections[marker_flag-1]];
13587  angPitch = new su2double*[nSpanWiseSections[marker_flag-1]];
13588  deltaAngPitch = new su2double*[nSpanWiseSections[marker_flag-1]];
13589  rank_loc = new int*[nSpanWiseSections[marker_flag-1]];
13590  minAngPitch = new su2double[nSpanWiseSections[marker_flag-1]];
13591  minIntAngPitch = new su2double[nSpanWiseSections[marker_flag-1]];
13592  maxAngPitch = new su2double[nSpanWiseSections[marker_flag-1]];
13593 
13594  nTotVertex_gb = new int[nSpanWiseSections[marker_flag-1]];
13595  nVertexSpanHalo = new int[nSpanWiseSections[marker_flag-1]];
13596  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13597  nTotVertex_gb[iSpan] = -1;
13598  nVertexSpanHalo[iSpan] = 0;
13599  minAngPitch[iSpan] = 10.0E+06;
13600  minIntAngPitch[iSpan] = 10.0E+06;
13601  maxAngPitch[iSpan] = -10.0E+06;
13602  }
13603 
13604  /*--- Initialize auxiliary pointers ---*/
13605  TurboNormal = new su2double[3];
13606  NormalArea = new su2double[3];
13607  ordered = new unsigned long* [nSpanWiseSections[marker_flag-1]];
13608  disordered = new unsigned long* [nSpanWiseSections[marker_flag-1]];
13609  oldVertex3D = new unsigned long* [nSpanWiseSections[marker_flag-1]];
13610  area = new su2double* [nSpanWiseSections[marker_flag-1]];
13611  unitnormal = new su2double** [nSpanWiseSections[marker_flag-1]];
13612  checkAssign = new bool* [nSpanWiseSections[marker_flag-1]];
13613 
13614  /*--- Initialize the new Vertex structure. The if statement ensures that these vectors are initialized
13615  * only once even if the routine is called more than once.---*/
13616 
13617  if (allocate){
13618  for (iMarker = 0; iMarker < nMarker; iMarker++){
13619  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
13620  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
13621  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
13622  nSpanSectionsByMarker[iMarker] = nSpanWiseSections[marker_flag-1];
13623  nVertexSpan[iMarker] = new long[nSpanWiseSections[marker_flag-1]];
13624  turbovertex[iMarker] = new CTurboVertex** [nSpanWiseSections[marker_flag-1]];
13625  nTotVertexSpan[iMarker] = new unsigned long [nSpanWiseSections[marker_flag-1] +1];
13626  MaxAngularCoord[iMarker] = new su2double [nSpanWiseSections[marker_flag-1]];
13627  MinAngularCoord[iMarker] = new su2double [nSpanWiseSections[marker_flag-1]];
13628  MinRelAngularCoord[iMarker] = new su2double [nSpanWiseSections[marker_flag-1]];
13629  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13630  nVertexSpan[iMarker][iSpan] = 0;
13631  turbovertex[iMarker][iSpan] = NULL;
13632  MinAngularCoord[iMarker][iSpan] = 10.0E+06;
13633  MaxAngularCoord[iMarker][iSpan] = -10.0E+06;
13634  MinRelAngularCoord[iMarker][iSpan] = 10.0E+06;
13635  }
13636  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1] +1; iSpan++){
13637  nTotVertexSpan[iMarker][iSpan] = 0;
13638  }
13639  }
13640  }
13641  }
13642  }
13643  }
13644 
13645  //this works only for turbomachinery rotating around the Z-Axes.
13646  // the reordering algorithm pitch-wise assumes that X-coordinate of each boundary vertex is positive so that reordering can be based on the Y-coordinate.
13647  for (iMarker = 0; iMarker < nMarker; iMarker++){
13648  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
13649  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
13650  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
13651 
13652  /*--- compute the amount of vertexes for each span-wise section to initialize the CTurboVertex pointers and auxiliary pointers ---*/
13653  for (iVertex = 0; (unsigned long)iVertex < nVertex[iMarker]; iVertex++) {
13654  iPoint = vertex[iMarker][iVertex]->GetNode();
13655  if (nDim == 3){
13656  dist = 10E+06;
13657  jSpan = -1;
13658  coord = node[iPoint]->GetCoord();
13659 
13660  switch (config->GetKind_TurboMachinery(val_iZone)){
13661  case CENTRIFUGAL: case CENTRIPETAL:
13662  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13663  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13664  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13665  jSpan=iSpan;
13666  }
13667  }
13668  break;
13669  case AXIAL:
13670  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13671  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13672  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13673  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13674  jSpan=iSpan;
13675  }
13676  }
13677  break;
13678  case CENTRIPETAL_AXIAL:
13679  if (marker_flag == OUTFLOW){
13680  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13681  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13682  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13683  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13684  jSpan=iSpan;
13685  }
13686  }
13687  }
13688  else{
13689  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13690  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13691  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13692  jSpan=iSpan;
13693  }
13694  }
13695  }
13696  break;
13697 
13698  case AXIAL_CENTRIFUGAL:
13699  if (marker_flag == INFLOW){
13700  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13701  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13702  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13703  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13704  jSpan=iSpan;
13705  }
13706  }
13707  }
13708  else{
13709  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13710  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13711  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13712  jSpan=iSpan;
13713  }
13714  }
13715  }
13716  break;
13717  }
13718  }
13719 
13720  /*--- 2D problem do not need span-wise separation---*/
13721  else{
13722  jSpan = 0;
13723  }
13724 
13725  if(node[iPoint]->GetDomain()){
13726  nVertexSpan[iMarker][jSpan]++;
13727  }
13728  nVertexSpanHalo[jSpan]++;
13729  }
13730 
13731  /*--- initialize the CTurboVertex pointers and auxiliary pointers ---*/
13732  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13733  if (allocate){
13734  turbovertex[iMarker][iSpan] = new CTurboVertex* [nVertexSpan[iMarker][iSpan]];
13735  for (iVertex = 0; iVertex < nVertexSpan[iMarker][iSpan]; iVertex++){
13736  turbovertex[iMarker][iSpan][iVertex] = NULL;
13737  }
13738  }
13739  ordered[iSpan] = new unsigned long [nVertexSpanHalo[iSpan]];
13740  disordered[iSpan] = new unsigned long [nVertexSpanHalo[iSpan]];
13741  oldVertex3D[iSpan] = new unsigned long [nVertexSpanHalo[iSpan]];
13742  checkAssign[iSpan] = new bool [nVertexSpanHalo[iSpan]];
13743  area[iSpan] = new su2double [nVertexSpanHalo[iSpan]];
13744  unitnormal[iSpan] = new su2double* [nVertexSpanHalo[iSpan]];
13745  for (iVertex = 0; iVertex < nVertexSpanHalo[iSpan]; iVertex++){
13746  unitnormal[iSpan][iVertex] = new su2double [nDim];
13747  }
13748  angPitch[iSpan] = new su2double [nVertexSpanHalo[iSpan]];
13749  deltaAngPitch[iSpan] = new su2double [nVertexSpanHalo[iSpan]];
13750  nVertexSpanHalo[iSpan] = 0;
13751  }
13752 
13753  /*--- store the vertexes in a ordered manner in span-wise directions but not yet ordered pitch-wise ---*/
13754  for (iVertex = 0; (unsigned long)iVertex < nVertex[iMarker]; iVertex++) {
13755  iPoint = vertex[iMarker][iVertex]->GetNode();
13756  if(nDim == 3){
13757  dist = 10E+06;
13758  jSpan = -1;
13759 
13760  coord = node[iPoint]->GetCoord();
13761  switch (config->GetKind_TurboMachinery(val_iZone)){
13762  case CENTRIFUGAL: case CENTRIPETAL:
13763  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13764  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13765  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13766  jSpan=iSpan;
13767  }
13768  }
13769  break;
13770  case AXIAL:
13771  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13772  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13773  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13774  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13775  jSpan=iSpan;
13776  }
13777  }
13778  break;
13779  case CENTRIPETAL_AXIAL:
13780  if(marker_flag == OUTFLOW){
13781  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13782  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13783  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13784  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13785  jSpan=iSpan;
13786  }
13787  }
13788  }else{
13789  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13790  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13791  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13792  jSpan=iSpan;
13793  }
13794  }
13795  }
13796  break;
13797 
13798  case AXIAL_CENTRIFUGAL:
13799  if(marker_flag == INFLOW){
13800  radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]);
13801  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13802  if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){
13803  dist= abs(radius-SpanWiseValue[marker_flag-1][iSpan]);
13804  jSpan=iSpan;
13805  }
13806  }
13807  }else{
13808  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13809  if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){
13810  dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]);
13811  jSpan=iSpan;
13812  }
13813  }
13814  }
13815  break;
13816  }
13817  }
13818  /*--- 2D problem do not need span-wise separation---*/
13819  else{
13820  jSpan = 0;
13821  }
13822  /*--- compute the face area associated with the vertex ---*/
13823  vertex[iMarker][iVertex]->GetNormal(NormalArea);
13824  for (iDim = 0; iDim < nDim; iDim++) NormalArea[iDim] = -NormalArea[iDim];
13825  Area = 0.0;
13826  for (iDim = 0; iDim < nDim; iDim++)
13827  Area += NormalArea[iDim]*NormalArea[iDim];
13828  Area = sqrt(Area);
13829  for (iDim = 0; iDim < nDim; iDim++) NormalArea[iDim] /= Area;
13830  /*--- store all the all the info into the auxiliary containers ---*/
13831  disordered[jSpan][nVertexSpanHalo[jSpan]] = iPoint;
13832  oldVertex3D[jSpan][nVertexSpanHalo[jSpan]] = iVertex;
13833  area[jSpan][nVertexSpanHalo[jSpan]] = Area;
13834  for (iDim = 0; iDim < nDim; iDim++){
13835  unitnormal[jSpan][nVertexSpanHalo[jSpan]][iDim] = NormalArea[iDim];
13836  }
13837  checkAssign[jSpan][nVertexSpanHalo[jSpan]] = false;
13838  nVertexSpanHalo[jSpan]++;
13839  }
13840 
13841  /*--- using the auxiliary container reordered the vertexes pitch-wise direction at each span ---*/
13842  // the reordering algorithm can be based on the Y-coordinate.
13843  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
13844 
13845  /*--- find the local minimum and maximum pitch-wise for each processor---*/
13846  min = 10E+06;
13847  minInt = 10E+06;
13848  max = -10E+06;
13849  for(iSpanVertex = 0; iSpanVertex < nVertexSpanHalo[iSpan]; iSpanVertex++){
13850  iPoint = disordered[iSpan][iSpanVertex];
13851  coord = node[iPoint]->GetCoord();
13852  /*--- find nodes at minimum pitch among all nodes---*/
13853  if (coord[1]<min){
13854  min = coord[1];
13855  if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){
13856  MinAngularCoord[iMarker][iSpan] = coord[1];
13857  }
13858  else{
13859  MinAngularCoord[iMarker][iSpan] = atan(coord[1]/coord[0]);
13860  }
13861  minAngPitch[iSpan]= MinAngularCoord[iMarker][iSpan];
13862  kSpanVertex =iSpanVertex;
13863  }
13864 
13865  /*--- find nodes at minimum pitch among the internal nodes---*/
13866  if (coord[1]<minInt){
13867  if(node[iPoint]->GetDomain()){
13868  minInt = coord[1];
13869  if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){
13870  minIntAngPitch[iSpan] = coord[1];
13871  }
13872  else{
13873  minIntAngPitch[iSpan] = atan(coord[1]/coord[0]);
13874  }
13875  }
13876  }
13877 
13878  /*--- find nodes at maximum pitch among the internal nodes---*/
13879  if (coord[1]>max){
13880  if(node[iPoint]->GetDomain()){
13881  max =coord[1];
13882  if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){
13883  MaxAngularCoord[iMarker][iSpan] = coord[1];
13884  }
13885  else{
13886  MaxAngularCoord[iMarker][iSpan] = atan(coord[1]/coord[0]);
13887  }
13888  maxAngPitch[iSpan]= MaxAngularCoord[iMarker][iSpan];
13889  }
13890  }
13891  }
13892 
13893  iInternalVertex = 0;
13894 
13895  /*--- reordering the vertex pitch-wise, store the ordered vertexes span-wise and pitch-wise---*/
13896  for(iSpanVertex = 0; iSpanVertex<nVertexSpanHalo[iSpan]; iSpanVertex++){
13897  dist = 10E+06;
13898  ordered[iSpan][iSpanVertex] = disordered[iSpan][kSpanVertex];
13899  checkAssign[iSpan][kSpanVertex] = true;
13900  coord = node[ordered[iSpan][iSpanVertex]]->GetCoord();
13901  target = coord[1];
13902  if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){
13903  angPitch[iSpan][iSpanVertex]=coord[1];
13904  }
13905  else{
13906  angPitch[iSpan][iSpanVertex]=atan(coord[1]/coord[0]);
13907  }
13908  if(iSpanVertex == 0){
13909  deltaAngPitch[iSpan][iSpanVertex]=0.0;
13910  }
13911  else{
13912  deltaAngPitch[iSpan][iSpanVertex]= angPitch[iSpan][iSpanVertex] - angPitch[iSpan][iSpanVertex - 1];
13913  }
13914  /*---create turbovertex structure only for the internal nodes---*/
13915  if(node[ordered[iSpan][iSpanVertex]]->GetDomain()){
13916  if (allocate){
13917  turbovertex[iMarker][iSpan][iInternalVertex] = new CTurboVertex(ordered[iSpan][iSpanVertex], nDim);
13918  }
13919  turbovertex[iMarker][iSpan][iInternalVertex]->SetArea(area[iSpan][kSpanVertex]);
13920  turbovertex[iMarker][iSpan][iInternalVertex]->SetNormal(unitnormal[iSpan][kSpanVertex]);
13921  turbovertex[iMarker][iSpan][iInternalVertex]->SetOldVertex(oldVertex3D[iSpan][kSpanVertex]);
13922  turbovertex[iMarker][iSpan][iInternalVertex]->SetAngularCoord(angPitch[iSpan][iSpanVertex]);
13923  turbovertex[iMarker][iSpan][iInternalVertex]->SetDeltaAngularCoord(deltaAngPitch[iSpan][iSpanVertex]);
13924  switch (config->GetKind_TurboMachinery(val_iZone)){
13925  case CENTRIFUGAL:
13926  Normal2 = 0.0;
13927  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
13928  if (marker_flag == INFLOW){
13929  TurboNormal[0] = -coord[0]/sqrt(Normal2);
13930  TurboNormal[1] = -coord[1]/sqrt(Normal2);
13931  TurboNormal[2] = 0.0;
13932  }else{
13933  TurboNormal[0] = coord[0]/sqrt(Normal2);
13934  TurboNormal[1] = coord[1]/sqrt(Normal2);
13935  TurboNormal[2] = 0.0;
13936  }
13937  break;
13938  case CENTRIPETAL:
13939  Normal2 = 0.0;
13940  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
13941  if (marker_flag == OUTFLOW){
13942  TurboNormal[0] = -coord[0]/sqrt(Normal2);
13943  TurboNormal[1] = -coord[1]/sqrt(Normal2);
13944  TurboNormal[2] = 0.0;
13945  }else{
13946  TurboNormal[0] = coord[0]/sqrt(Normal2);
13947  TurboNormal[1] = coord[1]/sqrt(Normal2);
13948  TurboNormal[2] = 0.0;
13949  }
13950  break;
13951  case AXIAL:
13952  Normal2 = 0.0;
13953  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
13954  if(nDim == 3){
13955  if (marker_flag == INFLOW){
13956  TurboNormal[0] = coord[0]/sqrt(Normal2);
13957  TurboNormal[1] = coord[1]/sqrt(Normal2);
13958  TurboNormal[2] = 0.0;
13959  }else{
13960  TurboNormal[0] = coord[0]/sqrt(Normal2);
13961  TurboNormal[1] = coord[1]/sqrt(Normal2);
13962  TurboNormal[2] = 0.0;
13963  }
13964  }
13965  else{
13966  if (marker_flag == INFLOW){
13967  TurboNormal[0] = -1.0;
13968  TurboNormal[1] = 0.0;
13969  TurboNormal[2] = 0.0;
13970  }else{
13971  TurboNormal[0] = 1.0;
13972  TurboNormal[1] = 0.0;
13973  TurboNormal[2] = 0.0;
13974  }
13975  }
13976 
13977  break;
13978  case CENTRIPETAL_AXIAL:
13979  Normal2 = 0.0;
13980  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
13981  if (marker_flag == INFLOW){
13982  TurboNormal[0] = coord[0]/sqrt(Normal2);
13983  TurboNormal[1] = coord[1]/sqrt(Normal2);
13984  TurboNormal[2] = 0.0;
13985  }else{
13986  TurboNormal[0] = coord[0]/sqrt(Normal2);
13987  TurboNormal[1] = coord[1]/sqrt(Normal2);
13988  TurboNormal[2] = 0.0;
13989  }
13990  break;
13991 
13992  case AXIAL_CENTRIFUGAL:
13993  Normal2 = 0.0;
13994  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
13995  if (marker_flag == INFLOW){
13996  TurboNormal[0] = coord[0]/sqrt(Normal2);
13997  TurboNormal[1] = coord[1]/sqrt(Normal2);
13998  TurboNormal[2] = 0.0;
13999  }else{
14000  TurboNormal[0] = coord[0]/sqrt(Normal2);
14001  TurboNormal[1] = coord[1]/sqrt(Normal2);
14002  TurboNormal[2] = 0.0;
14003  }
14004  break;
14005 
14006  }
14007  turbovertex[iMarker][iSpan][iInternalVertex]->SetTurboNormal(TurboNormal);
14008  iInternalVertex++;
14009  }
14010 
14011 
14012  for(jSpanVertex = 0; jSpanVertex<nVertexSpanHalo[iSpan]; jSpanVertex++){
14013  coord = node[disordered[iSpan][jSpanVertex]]->GetCoord();
14014  if(dist >= (coord[1] - target) && !checkAssign[iSpan][jSpanVertex] && (coord[1] - target) >= 0.0){
14015  dist= coord[1] - target;
14016  kSpanVertex =jSpanVertex;
14017  }
14018  }
14019  }
14020  }
14021 
14022  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14023 
14024  delete [] ordered[iSpan];
14025  delete [] disordered[iSpan];
14026  delete [] oldVertex3D[iSpan];
14027  delete [] checkAssign[iSpan];
14028  delete [] area[iSpan];
14029  delete [] angPitch[iSpan];
14030  delete [] deltaAngPitch[iSpan];
14031 
14032  for(iVertex=0; iVertex < nVertexSpanHalo[iSpan]; iVertex++){
14033  delete [] unitnormal[iSpan][iVertex];
14034  }
14035  delete [] unitnormal[iSpan];
14036  }
14037  }
14038  }
14039  }
14040  }
14041 
14042  /*--- to be set for all the processor to initialize an appropriate number of frequency for the NR BC ---*/
14043  nVertMax = 0;
14044 
14045  /*--- compute global max and min pitch per span ---*/
14046  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14047  nVert = 0;
14048 
14049 #ifdef HAVE_MPI
14050  MyMin = minAngPitch[iSpan]; minAngPitch[iSpan] = 10.0E+6;
14051  MyIntMin = minIntAngPitch[iSpan]; minIntAngPitch[iSpan] = 10.0E+6;
14052  MyMax = maxAngPitch[iSpan]; maxAngPitch[iSpan] = -10.0E+6;
14053 
14054  SU2_MPI::Allreduce(&MyMin, &minAngPitch[iSpan], 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
14055  SU2_MPI::Allreduce(&MyIntMin, &minIntAngPitch[iSpan], 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
14056  SU2_MPI::Allreduce(&MyMax, &maxAngPitch[iSpan], 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
14057 #endif
14058 
14059 
14060  /*--- compute the relative angular pitch with respect to the minimum value ---*/
14061 
14062  for (iMarker = 0; iMarker < nMarker; iMarker++){
14063  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14064  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14065  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14066  nVert = nVertexSpan[iMarker][iSpan];
14067  MinAngularCoord[iMarker][iSpan] = minAngPitch[iSpan];
14068  MaxAngularCoord[iMarker][iSpan] = maxAngPitch[iSpan];
14069  MinRelAngularCoord[iMarker][iSpan] = minIntAngPitch[iSpan] - minAngPitch[iSpan];
14070  for(iSpanVertex = 0; iSpanVertex< nVertexSpan[iMarker][iSpan]; iSpanVertex++){
14071  turbovertex[iMarker][iSpan][iSpanVertex]->SetRelAngularCoord(MinAngularCoord[iMarker][iSpan]);
14072  }
14073  }
14074  }
14075  }
14076  }
14077 
14078 
14079 #ifdef HAVE_MPI
14080  My_nVert = nVert;nVert = 0;
14081  SU2_MPI::Allreduce(&My_nVert, &nVert, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
14082 #endif
14083 
14084  /*--- to be set for all the processor to initialize an appropriate number of frequency for the NR BC ---*/
14085  if(nVert > nVertMax){
14086  SetnVertexSpanMax(marker_flag,nVert);
14087  }
14088  /*--- for all the processor should be known the amount of total turbovertex per span ---*/
14089  nTotVertex_gb[iSpan]= (int)nVert;
14090 
14091  for (iMarker = 0; iMarker < nMarker; iMarker++){
14092  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14093  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14094  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14095  nTotVertexSpan[iMarker][iSpan]= nVert;
14096  nTotVertexSpan[iMarker][nSpanWiseSections[marker_flag-1]]+= nVert;
14097  }
14098  }
14099  }
14100  }
14101  }
14102 
14103 
14104  /*--- Printing Tec file to check the global ordering of the turbovertex pitch-wise ---*/
14105  /*--- Send all the info to the MASTERNODE ---*/
14106 
14107  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14108  x_loc[iSpan] = new su2double[nTotVertex_gb[iSpan]];
14109  y_loc[iSpan] = new su2double[nTotVertex_gb[iSpan]];
14110  z_loc[iSpan] = new su2double[nTotVertex_gb[iSpan]];
14111  angCoord_loc[iSpan] = new su2double[nTotVertex_gb[iSpan]];
14112  deltaAngCoord_loc[iSpan] = new su2double[nTotVertex_gb[iSpan]];
14113  rank_loc[iSpan] = new int[nTotVertex_gb[iSpan]];
14114  for(iSpanVertex = 0; iSpanVertex<nTotVertex_gb[iSpan]; iSpanVertex++){
14115  x_loc[iSpan][iSpanVertex] = -1.0;
14116  y_loc[iSpan][iSpanVertex] = -1.0;
14117  z_loc[iSpan][iSpanVertex] = -1.0;
14118  angCoord_loc[iSpan][iSpanVertex] = -1.0;
14119  deltaAngCoord_loc[iSpan][iSpanVertex] = -1.0;
14120  rank_loc[iSpan][iSpanVertex] = -1;
14121  }
14122  }
14123 
14124  for (iMarker = 0; iMarker < nMarker; iMarker++){
14125  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14126  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14127  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14128  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14129  for(iSpanVertex = 0; iSpanVertex<nVertexSpan[iMarker][iSpan]; iSpanVertex++){
14130  iPoint = turbovertex[iMarker][iSpan][iSpanVertex]->GetNode();
14131  coord = node[iPoint]->GetCoord();
14132  x_loc[iSpan][iSpanVertex] = coord[0];
14133  y_loc[iSpan][iSpanVertex] = coord[1];
14134  if (nDim == 3){
14135  z_loc[iSpan][iSpanVertex] = coord[2];
14136  }
14137  else{
14138  z_loc[iSpan][iSpanVertex] = 0.0;
14139  }
14140  angCoord_loc[iSpan][iSpanVertex] = turbovertex[iMarker][iSpan][iSpanVertex]->GetRelAngularCoord();
14141  deltaAngCoord_loc[iSpan][iSpanVertex] = turbovertex[iMarker][iSpan][iSpanVertex]->GetDeltaAngularCoord();
14142  }
14143  }
14144  }
14145  }
14146  }
14147  }
14148 
14149 #ifdef HAVE_MPI
14150 
14151  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14152  if (rank == MASTER_NODE){
14153  x_gb = new su2double[nTotVertex_gb[iSpan]*size];
14154  y_gb = new su2double[nTotVertex_gb[iSpan]*size];
14155  z_gb = new su2double[nTotVertex_gb[iSpan]*size];
14156  angCoord_gb = new su2double[nTotVertex_gb[iSpan]*size];
14157  deltaAngCoord_gb = new su2double[nTotVertex_gb[iSpan]*size];
14158  checkAssign_gb = new bool[nTotVertex_gb[iSpan]*size];
14159 
14160  for(iSize= 0; iSize < size; iSize++){
14161  for(iSpanVertex = 0; iSpanVertex < nTotVertex_gb[iSpan]; iSpanVertex++){
14162  checkAssign_gb[iSize*nTotVertex_gb[iSpan] + iSpanVertex] = false;
14163  }
14164  }
14165  }
14166  SU2_MPI::Gather(y_loc[iSpan], nTotVertex_gb[iSpan] , MPI_DOUBLE, y_gb, nTotVertex_gb[iSpan], MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
14167  SU2_MPI::Gather(x_loc[iSpan], nTotVertex_gb[iSpan] , MPI_DOUBLE, x_gb, nTotVertex_gb[iSpan], MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
14168  SU2_MPI::Gather(z_loc[iSpan], nTotVertex_gb[iSpan] , MPI_DOUBLE, z_gb, nTotVertex_gb[iSpan], MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
14169  SU2_MPI::Gather(angCoord_loc[iSpan], nTotVertex_gb[iSpan] , MPI_DOUBLE, angCoord_gb, nTotVertex_gb[iSpan], MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
14170  SU2_MPI::Gather(deltaAngCoord_loc[iSpan], nTotVertex_gb[iSpan] , MPI_DOUBLE, deltaAngCoord_gb, nTotVertex_gb[iSpan], MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD);
14171 
14172  if (rank == MASTER_NODE){
14173  for(iSpanVertex = 0; iSpanVertex<nTotVertex_gb[iSpan]; iSpanVertex++){
14174  x_loc[iSpan][iSpanVertex] = -1.0;
14175  y_loc[iSpan][iSpanVertex] = -1.0;
14176  z_loc[iSpan][iSpanVertex] = -1.0;
14177  angCoord_loc[iSpan][iSpanVertex] = -1.0;
14178  deltaAngCoord_loc[iSpan][iSpanVertex] = -1.0;
14179  }
14180 
14181 
14182 
14183  min = 10.0E+06;
14184  for(iSize= 0; iSize < size; iSize++){
14185  if (angCoord_gb[iSize*nTotVertex_gb[iSpan]] < min && angCoord_gb[iSize*nTotVertex_gb[iSpan]] >= 0.0){
14186  kSize = iSize;
14187  min = angCoord_gb[iSize*nTotVertex_gb[iSpan]];
14188  }
14189  }
14190 
14191  kSpanVertex = 0;
14192  for(iSpanVertex = 0; iSpanVertex < nTotVertex_gb[iSpan]; iSpanVertex++){
14193  x_loc[iSpan][iSpanVertex] = x_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex];
14194  y_loc[iSpan][iSpanVertex] = y_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex];
14195  z_loc[iSpan][iSpanVertex] = z_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex];
14196  angCoord_loc[iSpan][iSpanVertex] = angCoord_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex];
14197  deltaAngCoord_loc[iSpan][iSpanVertex] = deltaAngCoord_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex];
14198  rank_loc[iSpan][iSpanVertex] = kSize;
14199  target = angCoord_loc[iSpan][iSpanVertex];
14200  checkAssign_gb[kSize*nTotVertex_gb[iSpan] + kSpanVertex] = true;
14201  min = 10.0E+06;
14202  for(jSize= 0; jSize < size; jSize++){
14203  for(jSpanVertex = 0; jSpanVertex < nTotVertex_gb[iSpan]; jSpanVertex++){
14204  if (angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] < min && (angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] - target) >= 0.0 && !checkAssign_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex]){
14205  kSize = jSize;
14206  kSpanVertex = jSpanVertex;
14207  min = angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex];
14208  }
14209  }
14210  }
14211  }
14212 
14213 
14214  delete [] x_gb; delete [] y_gb; delete [] z_gb; delete [] angCoord_gb; delete [] deltaAngCoord_gb; delete[] checkAssign_gb;
14215 
14216  }
14217  }
14218 
14219 #endif
14220 
14221  if (rank == MASTER_NODE){
14222  if (marker_flag == INFLOW && val_iZone ==0){
14223  std::string sPath = "TURBOMACHINERY";
14224  mode_t nMode = 0733; // UNIX style permissions
14225  int nError = 0;
14226 #if defined(_WIN32)
14227 #ifdef __MINGW32__
14228  nError = mkdir(sPath.c_str()); // MINGW on Windows
14229 #else
14230  nError = _mkdir(sPath.c_str()); // can be used on Windows
14231 #endif
14232 #else
14233  nError = mkdir(sPath.c_str(),nMode); // can be used on non-Windows
14234 #endif
14235  if (nError != 0) {
14236  cout << "TURBOMACHINERY folder creation failed." <<endl;
14237  }
14238  }
14239  if (marker_flag == INFLOW){
14240  multizone_filename = "TURBOMACHINERY/spanwise_division_inflow.dat";
14241  }
14242  else{
14243  multizone_filename = "TURBOMACHINERY/spanwise_division_outflow.dat";
14244  }
14245  char buffer[50];
14246 
14247  if (GetnZone() > 1){
14248  unsigned short lastindex = multizone_filename.find_last_of(".");
14249  multizone_filename = multizone_filename.substr(0, lastindex);
14250  SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(val_iZone));
14251  multizone_filename.append(string(buffer));
14252  }
14253 
14254  // File to print the vector x_loc, y_loc, z_loc, globIdx_loc to check vertex ordering
14255  ofstream myfile;
14256  myfile.open (multizone_filename.data(), ios::out | ios::trunc);
14257  myfile.setf(ios::uppercase | ios::scientific);
14258  myfile.precision(8);
14259 
14260  myfile << "TITLE = \"Global index visualization file\"" << endl;
14261  myfile << "VARIABLES =" << endl;
14262  myfile.width(10); myfile << "\"iSpan\"";
14263  myfile.width(20); myfile << "\"x_coord\"" ;
14264  myfile.width(20); myfile << "\"y_coord\"" ;
14265  myfile.width(20); myfile << "\"z_coord\"" ;
14266  myfile.width(20); myfile << "\"radius\"" ;
14267  myfile.width(20); myfile << "\"Relative Angular Coord \"" ;
14268  myfile.width(20); myfile << "\"Delta Angular Coord \"" ;
14269  myfile.width(20); myfile << "\"processor\"" <<endl;
14270  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14271  for(iSpanVertex = 0; iSpanVertex < nTotVertex_gb[iSpan]; iSpanVertex++){
14272  radius = sqrt(x_loc[iSpan][iSpanVertex]*x_loc[iSpan][iSpanVertex] + y_loc[iSpan][iSpanVertex]*y_loc[iSpan][iSpanVertex]);
14273  myfile.width(10); myfile << iSpan;
14274  myfile.width(20); myfile << x_loc[iSpan][iSpanVertex];
14275  myfile.width(20); myfile << y_loc[iSpan][iSpanVertex];
14276  myfile.width(20); myfile << z_loc[iSpan][iSpanVertex];
14277  myfile.width(20); myfile << radius;
14278  if (nDim ==2 && config->GetKind_TurboMachinery(val_iZone)){
14279  myfile.width(20); myfile << angCoord_loc[iSpan][iSpanVertex];
14280  myfile.width(20); myfile << deltaAngCoord_loc[iSpan][iSpanVertex];
14281  }
14282  else{
14283  myfile.width(20); myfile << angCoord_loc[iSpan][iSpanVertex]*180.0/PI_NUMBER;
14284  myfile.width(20); myfile << deltaAngCoord_loc[iSpan][iSpanVertex]*180.0/PI_NUMBER;
14285  }
14286  myfile.width(20); myfile << rank_loc[iSpan][iSpanVertex]<<endl;
14287  }
14288  myfile << endl;
14289  }
14290  }
14291 
14292 
14293  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14294  delete [] x_loc[iSpan];
14295  delete [] y_loc[iSpan];
14296  delete [] z_loc[iSpan];
14297  delete [] angCoord_loc[iSpan];
14298  delete [] deltaAngCoord_loc[iSpan];
14299  delete [] rank_loc[iSpan];
14300 
14301  }
14302 
14303 
14304  delete [] area;
14305  delete [] ordered;
14306  delete [] disordered;
14307  delete [] oldVertex3D;
14308  delete [] checkAssign;
14309  delete [] TurboNormal;
14310  delete [] unitnormal;
14311  delete [] NormalArea;
14312  delete [] x_loc;
14313  delete [] y_loc;
14314  delete [] z_loc;
14315  delete [] angCoord_loc;
14316  delete [] nTotVertex_gb;
14317  delete [] nVertexSpanHalo;
14318  delete [] angPitch;
14319  delete [] deltaAngPitch;
14320  delete [] deltaAngCoord_loc;
14321  delete [] rank_loc;
14322  delete [] minAngPitch;
14323  delete [] maxAngPitch;
14324  delete [] minIntAngPitch;
14325 
14326 }
14327 
14328 
14329 void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag) {
14330  unsigned short iMarker, iMarkerTP, iSpan, iDim;
14331  long iSpanVertex, iPoint;
14332  su2double *coord, *TurboNormal, Normal2;
14333 
14334  /*--- Initialize auxiliary pointers ---*/
14335  TurboNormal = new su2double[3];
14336 
14337  for (iMarker = 0; iMarker < nMarker; iMarker++){
14338  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14339  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14340  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14341  for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14342  for(iSpanVertex = 0; iSpanVertex<nVertexSpan[iMarker][iSpan]; iSpanVertex++){
14343  iPoint = turbovertex[iMarker][iSpan][iSpanVertex]->GetNode();
14344  coord = node[iPoint]->GetCoord();
14345  /*--- compute appropriate turbo normal ---*/
14346  switch (config->GetKind_TurboMachinery(val_iZone)){
14347  case CENTRIFUGAL:
14348  Normal2 = 0.0;
14349  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
14350  if (marker_flag == INFLOW){
14351  TurboNormal[0] = -coord[0]/sqrt(Normal2);
14352  TurboNormal[1] = -coord[1]/sqrt(Normal2);
14353  TurboNormal[2] = 0.0;
14354  }else{
14355  TurboNormal[0] = coord[0]/sqrt(Normal2);
14356  TurboNormal[1] = coord[1]/sqrt(Normal2);
14357  TurboNormal[2] = 0.0;
14358  }
14359  break;
14360  case CENTRIPETAL:
14361  Normal2 = 0.0;
14362  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
14363  if (marker_flag == OUTFLOW){
14364  TurboNormal[0] = -coord[0]/sqrt(Normal2);
14365  TurboNormal[1] = -coord[1]/sqrt(Normal2);
14366  TurboNormal[2] = 0.0;
14367  }else{
14368  TurboNormal[0] = coord[0]/sqrt(Normal2);
14369  TurboNormal[1] = coord[1]/sqrt(Normal2);
14370  TurboNormal[2] = 0.0;
14371  }
14372  break;
14373  case AXIAL:
14374  Normal2 = 0.0;
14375  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
14376  if(nDim == 3){
14377  if (marker_flag == INFLOW){
14378  TurboNormal[0] = coord[0]/sqrt(Normal2);
14379  TurboNormal[1] = coord[1]/sqrt(Normal2);
14380  TurboNormal[2] = 0.0;
14381  }else{
14382  TurboNormal[0] = coord[0]/sqrt(Normal2);
14383  TurboNormal[1] = coord[1]/sqrt(Normal2);
14384  TurboNormal[2] = 0.0;
14385  }
14386  }
14387  else{
14388  if (marker_flag == INFLOW){
14389  TurboNormal[0] = -1.0;
14390  TurboNormal[1] = 0.0;
14391  TurboNormal[2] = 0.0;
14392  }else{
14393  TurboNormal[0] = 1.0;
14394  TurboNormal[1] = 0.0;
14395  TurboNormal[2] = 0.0;
14396  }
14397  }
14398 
14399  break;
14400  case CENTRIPETAL_AXIAL:
14401  Normal2 = 0.0;
14402  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
14403  if (marker_flag == INFLOW){
14404  TurboNormal[0] = coord[0]/sqrt(Normal2);
14405  TurboNormal[1] = coord[1]/sqrt(Normal2);
14406  TurboNormal[2] = 0.0;
14407  }else{
14408  TurboNormal[0] = coord[0]/sqrt(Normal2);
14409  TurboNormal[1] = coord[1]/sqrt(Normal2);
14410  TurboNormal[2] = 0.0;
14411  }
14412  break;
14413 
14414  case AXIAL_CENTRIFUGAL:
14415  Normal2 = 0.0;
14416  for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim];
14417  if (marker_flag == INFLOW){
14418  TurboNormal[0] = coord[0]/sqrt(Normal2);
14419  TurboNormal[1] = coord[1]/sqrt(Normal2);
14420  TurboNormal[2] = 0.0;
14421  }else{
14422  TurboNormal[0] = coord[0]/sqrt(Normal2);
14423  TurboNormal[1] = coord[1]/sqrt(Normal2);
14424  TurboNormal[2] = 0.0;
14425  }
14426  break;
14427  }
14428 
14429  /*--- store the new turbo normal ---*/
14430  turbovertex[iMarker][iSpan][iSpanVertex]->SetTurboNormal(TurboNormal);
14431  }
14432  }
14433  }
14434  }
14435  }
14436  }
14437 
14438  delete [] TurboNormal;
14439 }
14440 
14441 void CPhysicalGeometry::SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {
14442 
14443  unsigned short iMarker, iMarkerTP, iSpan, iDim;
14444  unsigned long iPoint;
14445  su2double *TurboNormal,*coord, *Normal, turboNormal2, Normal2, *gridVel, TotalArea, TotalRadius, radius;
14446  su2double *TotalTurboNormal,*TotalNormal, *TotalGridVel, Area;
14447  long iVertex;
14448  /*-- Variables declaration and allocation ---*/
14449  TotalTurboNormal = new su2double[nDim];
14450  TotalNormal = new su2double[nDim];
14451  TurboNormal = new su2double[nDim];
14452  TotalGridVel = new su2double[nDim];
14453  Normal = new su2double[nDim];
14454 
14455  bool grid_movement = config->GetGrid_Movement();
14456 #ifdef HAVE_MPI
14457  su2double MyTotalArea, MyTotalRadius, *MyTotalTurboNormal= NULL, *MyTotalNormal= NULL, *MyTotalGridVel= NULL;
14458 #endif
14459 
14460  /*--- Intialization of the vector for the interested boundary ---*/
14461  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){
14462  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14463  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14464  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14465  if(allocate){
14466  nSpanSectionsByMarker[iMarker] = nSpanWiseSections[marker_flag-1];
14467  AverageTurboNormal[iMarker] = new su2double *[nSpanWiseSections[marker_flag-1] + 1];
14468  AverageNormal[iMarker] = new su2double *[nSpanWiseSections[marker_flag-1] + 1];
14469  AverageGridVel[iMarker] = new su2double *[nSpanWiseSections[marker_flag-1] + 1];
14470  AverageTangGridVel[iMarker] = new su2double [nSpanWiseSections[marker_flag-1] + 1];
14471  SpanArea[iMarker] = new su2double [nSpanWiseSections[marker_flag-1] + 1];
14472  TurboRadius[iMarker] = new su2double [nSpanWiseSections[marker_flag-1] + 1];
14473  for (iSpan= 0; iSpan < nSpanWiseSections[marker_flag-1] + 1; iSpan++){
14474  AverageTurboNormal[iMarker][iSpan] = new su2double [nDim];
14475  AverageNormal[iMarker][iSpan] = new su2double [nDim];
14476  AverageGridVel[iMarker][iSpan] = new su2double [nDim];
14477  }
14478  }
14479  for (iSpan= 0; iSpan < nSpanWiseSections[marker_flag-1] + 1; iSpan++){
14480  AverageTangGridVel[iMarker][iSpan] = 0.0;
14481  SpanArea[iMarker][iSpan] = 0.0;
14482  TurboRadius[iMarker][iSpan] = 0.0;
14483  for(iDim=0; iDim < nDim; iDim++){
14484  AverageTurboNormal[iMarker][iSpan][iDim] = 0.0;
14485  AverageNormal[iMarker][iSpan][iDim] = 0.0;
14486  AverageGridVel[iMarker][iSpan][iDim] = 0.0;
14487  }
14488  }
14489  }
14490  }
14491  }
14492  }
14493 
14494 
14495 
14496  /*--- start computing the average quantities span wise --- */
14497  for (iSpan= 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){
14498 
14499  /*--- Forces initialization for contenitors to zero ---*/
14500  for (iDim=0; iDim<nDim; iDim++) {
14501  TotalTurboNormal[iDim] =0.0;
14502  TotalNormal[iDim] =0.0;
14503  TotalGridVel[iDim] =0.0;
14504  }
14505  TotalArea = 0.0;
14506  TotalRadius = 0.0;
14507  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){
14508  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14509  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14510  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14511  for(iVertex = 0; iVertex < nVertexSpan[iMarker][iSpan]; iVertex++){
14512  iPoint = turbovertex[iMarker][iSpan][iVertex]->GetNode();
14513  turbovertex[iMarker][iSpan][iVertex]->GetTurboNormal(TurboNormal);
14514  turbovertex[iMarker][iSpan][iVertex]->GetNormal(Normal);
14515  coord = node[iPoint]->GetCoord();
14516 
14517  if (nDim == 3){
14518  radius = sqrt(coord[0]*coord[0] + coord[1]*coord[1]);
14519  }
14520  else{
14521  radius = 0.0;
14522  }
14523  Area = turbovertex[iMarker][iSpan][iVertex]->GetArea();
14524  TotalArea += Area;
14525  TotalRadius += radius;
14526  for (iDim = 0; iDim < nDim; iDim++) {
14527  TotalTurboNormal[iDim] +=TurboNormal[iDim];
14528  TotalNormal[iDim] +=Normal[iDim];
14529  }
14530  if (grid_movement){
14531  gridVel = node[iPoint]->GetGridVel();
14532  for (iDim = 0; iDim < nDim; iDim++) TotalGridVel[iDim] +=gridVel[iDim];
14533  }
14534  }
14535  }
14536  }
14537  }
14538  }
14539 
14540 #ifdef HAVE_MPI
14541 
14542  MyTotalArea = TotalArea; TotalArea = 0;
14543  MyTotalRadius = TotalRadius; TotalRadius = 0;
14544  SU2_MPI::Allreduce(&MyTotalArea, &TotalArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
14545  SU2_MPI::Allreduce(&MyTotalRadius, &TotalRadius, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
14546 
14547  MyTotalTurboNormal = new su2double[nDim];
14548  MyTotalNormal = new su2double[nDim];
14549  MyTotalGridVel = new su2double[nDim];
14550 
14551  for (iDim = 0; iDim < nDim; iDim++) {
14552  MyTotalTurboNormal[iDim] = TotalTurboNormal[iDim];
14553  TotalTurboNormal[iDim] = 0.0;
14554  MyTotalNormal[iDim] = TotalNormal[iDim];
14555  TotalNormal[iDim] = 0.0;
14556  MyTotalGridVel[iDim] = TotalGridVel[iDim];
14557  TotalGridVel[iDim] = 0.0;
14558  }
14559 
14560  SU2_MPI::Allreduce(MyTotalTurboNormal, TotalTurboNormal, nDim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
14561  SU2_MPI::Allreduce(MyTotalNormal, TotalNormal, nDim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
14562  SU2_MPI::Allreduce(MyTotalGridVel, TotalGridVel, nDim, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
14563 
14564  delete [] MyTotalTurboNormal;delete [] MyTotalNormal; delete [] MyTotalGridVel;
14565 
14566 #endif
14567 
14568  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){
14569  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14570  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14571  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14572 
14573 
14574  SpanArea[iMarker][iSpan] = TotalArea;
14575  TurboRadius[iMarker][iSpan] = TotalRadius/nTotVertexSpan[iMarker][iSpan];
14576 
14577  turboNormal2 = 0.0;
14578  Normal2 = 0.0;
14579  for (iDim = 0; iDim < nDim; iDim++){
14580  turboNormal2 += TotalTurboNormal[iDim]*TotalTurboNormal[iDim];
14581  Normal2 += TotalNormal[iDim]*TotalNormal[iDim];
14582  }
14583  for (iDim = 0; iDim < nDim; iDim++){
14584  AverageTurboNormal[iMarker][iSpan][iDim] = TotalTurboNormal[iDim]/sqrt(turboNormal2);
14585  AverageNormal[iMarker][iSpan][iDim] = TotalNormal[iDim]/sqrt(Normal2);
14586  }
14587  if (grid_movement){
14588  for (iDim = 0; iDim < nDim; iDim++){
14589  AverageGridVel[iMarker][iSpan][iDim] =TotalGridVel[iDim]/nTotVertexSpan[iMarker][iSpan];
14590  }
14591  switch (config->GetKind_TurboMachinery(val_iZone)){
14592  case CENTRIFUGAL:case CENTRIPETAL:
14593  if (marker_flag == INFLOW ){
14594  AverageTangGridVel[iMarker][iSpan]= -(AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]);
14595  }
14596  else{
14597  AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0];
14598  }
14599  break;
14600  case AXIAL:
14601  if (marker_flag == INFLOW && nDim == 2){
14602  AverageTangGridVel[iMarker][iSpan]= -AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1] + AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0];
14603  }
14604  else{
14605  AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0];
14606  }
14607  break;
14608  case CENTRIPETAL_AXIAL:
14609  if (marker_flag == OUTFLOW){
14610  AverageTangGridVel[iMarker][iSpan]= (AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]);
14611  }
14612  else{
14613  AverageTangGridVel[iMarker][iSpan]= -(AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]);
14614  }
14615  break;
14616  case AXIAL_CENTRIFUGAL:
14617  if (marker_flag == INFLOW)
14618  {
14619  AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0];
14620  }else
14621  {
14622  AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0];
14623  }
14624  break;
14625 
14626  default:
14627  SU2_MPI::Error("Tang grid velocity NOT IMPLEMENTED YET for this configuration", CURRENT_FUNCTION);
14628  break;
14629  }
14630  }
14631 
14632  /*--- Compute the 1D average values ---*/
14633  AverageTangGridVel[iMarker][nSpanWiseSections[marker_flag-1]] += AverageTangGridVel[iMarker][iSpan]/nSpanWiseSections[marker_flag-1];
14634  SpanArea[iMarker][nSpanWiseSections[marker_flag-1]] += SpanArea[iMarker][iSpan];
14635  for(iDim=0; iDim < nDim; iDim++){
14636  AverageTurboNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim] += AverageTurboNormal[iMarker][iSpan][iDim];
14637  AverageNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim] += AverageNormal[iMarker][iSpan][iDim];
14638  AverageGridVel[iMarker][nSpanWiseSections[marker_flag-1]][iDim] += AverageGridVel[iMarker][iSpan][iDim]/nSpanWiseSections[marker_flag-1];
14639 
14640  }
14641  }
14642  }
14643  }
14644  }
14645  }
14646 
14647  /*--- Normalize 1D normals---*/
14648  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){
14649  for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14650  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14651  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag){
14652  turboNormal2 = 0.0;
14653  Normal2 = 0.0;
14654 
14655  for (iDim = 0; iDim < nDim; iDim++){
14656  turboNormal2 += AverageTurboNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim]*AverageTurboNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim];
14657  Normal2 += AverageNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim]*AverageNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim];
14658  }
14659  for (iDim = 0; iDim < nDim; iDim++){
14660  AverageTurboNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim] /=sqrt(turboNormal2);
14661  AverageNormal[iMarker][nSpanWiseSections[marker_flag-1]][iDim] /=sqrt(Normal2);
14662  }
14663  }
14664  }
14665  }
14666  }
14667 
14668 
14669  delete [] TotalTurboNormal;
14670  delete [] TotalNormal;
14671  delete [] TotalGridVel;
14672  delete [] TurboNormal;
14673  delete [] Normal;
14674 
14675 }
14676 
14677 
14679 
14680  unsigned short iMarker, iMarkerTP;
14681  unsigned short iSpan, iDim;
14682  int markerTP;
14683  su2double nBlades;
14684  unsigned short nSpanWiseSections = config->GetnSpanWiseSections();
14685 
14686  su2double tangGridVelIn, tangGridVelOut;
14687  su2double areaIn, areaOut, pitchIn, Pitch;
14688  su2double radiusIn, radiusOut, *turboNormal;
14689 
14690  turboNormal = new su2double[nDim];
14691  Pitch = 0.0;
14692 
14693  if(allocate){
14694  for (iMarkerTP=0; iMarkerTP < config->GetnMarker_TurboPerformance(); iMarkerTP++){
14695  SpanAreaIn[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14696  TangGridVelIn[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14697  TurboRadiusIn[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14698  SpanAreaOut[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14699  TangGridVelOut[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14700  TurboRadiusOut[iMarkerTP] = new su2double[config->GetnSpanMaxAllZones() +1];
14701 
14702  for (iSpan= 0; iSpan < config->GetnSpanMaxAllZones() + 1 ; iSpan++){
14703  SpanAreaIn[iMarkerTP][iSpan] = 0.0;
14704  TangGridVelIn[iMarkerTP][iSpan] = 0.0;
14705  TurboRadiusIn[iMarkerTP][iSpan] = 0.0;
14706  SpanAreaOut[iMarkerTP][iSpan] = 0.0;
14707  TangGridVelOut[iMarkerTP][iSpan] = 0.0;
14708  TurboRadiusOut[iMarkerTP][iSpan] = 0.0;
14709  }
14710  }
14711  }
14712 
14713 
14714 
14715  for (iSpan= 0; iSpan < nSpanWiseSections + 1 ; iSpan++){
14716 #ifdef HAVE_MPI
14717  unsigned short i, n1, n2, n1t,n2t;
14718  su2double *TurbGeoIn= NULL,*TurbGeoOut= NULL;
14719  su2double *TotTurbGeoIn = NULL,*TotTurbGeoOut = NULL;
14720  int *TotMarkerTP;
14721 
14722  n1 = 6;
14723  n2 = 3;
14724  n1t = n1*size;
14725  n2t = n2*size;
14726  TurbGeoIn = new su2double[n1];
14727  TurbGeoOut = new su2double[n2];
14728 
14729  for (i=0;i<n1;i++)
14730  TurbGeoIn[i] = -1.0;
14731  for (i=0;i<n2;i++)
14732  TurbGeoOut[i] = -1.0;
14733 #endif
14734  pitchIn = 0.0;
14735  areaIn = -1.0;
14736  tangGridVelIn = -1.0;
14737  radiusIn = -1.0;
14738  for(iDim = 0; iDim < nDim; iDim++){
14739  turboNormal[iDim] = -1.0;
14740  }
14741 
14742  areaOut = -1.0;
14743  tangGridVelOut = -1.0;
14744  radiusOut = -1.0;
14745 
14746  markerTP = -1;
14747 
14748  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){
14749  for (iMarkerTP = 1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){
14750  if (config->GetMarker_All_Turbomachinery(iMarker) == iMarkerTP){
14751  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == INFLOW){
14752  markerTP = iMarkerTP;
14753  if (iSpan < nSpanWiseSections){
14754  pitchIn = MaxAngularCoord[iMarker][iSpan] - MinAngularCoord[iMarker][iSpan];
14755  }
14756  areaIn = SpanArea[iMarker][iSpan];
14757  tangGridVelIn = AverageTangGridVel[iMarker][iSpan];
14758  radiusIn = TurboRadius[iMarker][iSpan];
14759  for(iDim = 0; iDim < nDim; iDim++) turboNormal[iDim] = AverageTurboNormal[iMarker][iSpan][iDim];
14760 
14761 
14762 #ifdef HAVE_MPI
14763  TurbGeoIn[0] = areaIn;
14764  TurbGeoIn[1] = tangGridVelIn;
14765  TurbGeoIn[2] = radiusIn;
14766  TurbGeoIn[3] = turboNormal[0];
14767  TurbGeoIn[4] = turboNormal[1];
14768  TurbGeoIn[5] = pitchIn;
14769 #endif
14770  }
14771 
14772  /*--- retrieve outlet information ---*/
14773  if (config->GetMarker_All_TurbomachineryFlag(iMarker) == OUTFLOW){
14774  if (iSpan < nSpanWiseSections){
14775  pitchIn = MaxAngularCoord[iMarker][iSpan] - MinAngularCoord[iMarker][iSpan];
14776  }
14777  areaOut = SpanArea[iMarker][iSpan];
14778  tangGridVelOut = AverageTangGridVel[iMarker][iSpan];
14779  radiusOut = TurboRadius[iMarker][iSpan];
14780 #ifdef HAVE_MPI
14781  TurbGeoOut[0] = areaOut;
14782  TurbGeoOut[1] = tangGridVelOut;
14783  TurbGeoOut[2] = radiusOut;
14784 #endif
14785  }
14786  }
14787  }
14788  }
14789 
14790 #ifdef HAVE_MPI
14791  TotTurbGeoIn = new su2double[n1t];
14792  TotTurbGeoOut = new su2double[n2t];
14793  for (i=0;i<n1t;i++)
14794  TotTurbGeoIn[i] = -1.0;
14795  for (i=0;i<n2t;i++)
14796  TotTurbGeoOut[i] = -1.0;
14797  TotMarkerTP = new int[size];
14798  for(i=0; i<size; i++){
14799  TotMarkerTP[i] = -1;
14800  }
14801 
14802  SU2_MPI::Allgather(TurbGeoIn, n1, MPI_DOUBLE, TotTurbGeoIn, n1, MPI_DOUBLE, MPI_COMM_WORLD);
14803  SU2_MPI::Allgather(TurbGeoOut, n2, MPI_DOUBLE,TotTurbGeoOut, n2, MPI_DOUBLE, MPI_COMM_WORLD);
14804  SU2_MPI::Allgather(&markerTP, 1, MPI_INT,TotMarkerTP, 1, MPI_INT, MPI_COMM_WORLD);
14805 
14806  delete [] TurbGeoIn, delete [] TurbGeoOut;
14807 
14808 
14809  for (i=0;i<size;i++){
14810  if(TotTurbGeoIn[n1*i] > 0.0){
14811  areaIn = 0.0;
14812  areaIn = TotTurbGeoIn[n1*i];
14813  tangGridVelIn = 0.0;
14814  tangGridVelIn = TotTurbGeoIn[n1*i+1];
14815  radiusIn = 0.0;
14816  radiusIn = TotTurbGeoIn[n1*i+2];
14817  turboNormal[0] = 0.0;
14818  turboNormal[0] = TotTurbGeoIn[n1*i+3];
14819  turboNormal[1] = 0.0;
14820  turboNormal[1] = TotTurbGeoIn[n1*i+4];
14821  pitchIn = 0.0;
14822  pitchIn = TotTurbGeoIn[n1*i+5];
14823 
14824  markerTP = -1;
14825  markerTP = TotMarkerTP[i];
14826  }
14827 
14828  if(TotTurbGeoOut[n2*i] > 0.0){
14829  areaOut = 0.0;
14830  areaOut = TotTurbGeoOut[n2*i];
14831  tangGridVelOut = 0.0;
14832  tangGridVelOut = TotTurbGeoOut[n2*i+1];
14833  radiusOut = 0.0;
14834  radiusOut = TotTurbGeoOut[n2*i+2];
14835  }
14836  }
14837 
14838  delete [] TotTurbGeoIn, delete [] TotTurbGeoOut; delete [] TotMarkerTP;
14839 
14840 
14841 #endif
14842 
14843  Pitch +=pitchIn/nSpanWiseSections;
14844 
14845  if (iSpan == nSpanWiseSections) {
14846  config->SetFreeStreamTurboNormal(turboNormal);
14847  if (config->GetKind_TurboMachinery(config->GetiZone()) == AXIAL && nDim == 2){
14848  nBlades = 1/Pitch;
14849  }
14850  else{
14851  nBlades = 2*PI_NUMBER/Pitch;
14852  }
14853  config->SetnBlades(config->GetiZone(), nBlades);
14854  }
14855 
14856  if (rank == MASTER_NODE){
14857  /*----Quantities needed for computing the turbomachinery performance -----*/
14858  SpanAreaIn[markerTP -1][iSpan] = areaIn;
14859  TangGridVelIn[markerTP -1][iSpan] = tangGridVelIn;
14860  TurboRadiusIn[markerTP -1][iSpan] = radiusIn;
14861 
14862  SpanAreaOut[markerTP -1][iSpan] = areaOut;
14863  TangGridVelOut[markerTP -1][iSpan] = tangGridVelOut;
14864  TurboRadiusOut[markerTP -1][iSpan] = radiusOut;
14865  }
14866  }
14867  delete [] turboNormal;
14868 
14869 }
14870 
14871 
14873  unsigned short nNode, iDim, iMarker, iNode;
14874  unsigned long elem_poin, edge_poin, iElem, iEdge;
14875  su2double **Coord;
14876 
14877  /*--- Compute the center of gravity for elements ---*/
14878 
14879  for (iElem = 0; iElem<nElem; iElem++) {
14880  nNode = elem[iElem]->GetnNodes();
14881  Coord = new su2double* [nNode];
14882 
14883  /*--- Store the coordinates for all the element nodes ---*/
14884 
14885  for (iNode = 0; iNode < nNode; iNode++) {
14886  elem_poin = elem[iElem]->GetNode(iNode);
14887  Coord[iNode] = new su2double [nDim];
14888  for (iDim = 0; iDim < nDim; iDim++)
14889  Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim);
14890  }
14891 
14892  /*--- Compute the element CG coordinates ---*/
14893 
14894  elem[iElem]->SetCoord_CG(Coord);
14895 
14896  for (iNode = 0; iNode < nNode; iNode++)
14897  if (Coord[iNode] != NULL) delete[] Coord[iNode];
14898  if (Coord != NULL) delete[] Coord;
14899  }
14900 
14901  /*--- Center of gravity for face elements ---*/
14902 
14903  for (iMarker = 0; iMarker < nMarker; iMarker++)
14904  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) {
14905  nNode = bound[iMarker][iElem]->GetnNodes();
14906  Coord = new su2double* [nNode];
14907 
14908  /*--- Store the coordinates for all the element nodes ---*/
14909 
14910  for (iNode = 0; iNode < nNode; iNode++) {
14911  elem_poin = bound[iMarker][iElem]->GetNode(iNode);
14912  Coord[iNode] = new su2double [nDim];
14913  for (iDim = 0; iDim < nDim; iDim++)
14914  Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim);
14915  }
14916  /*--- Compute the element CG coordinates ---*/
14917 
14918  bound[iMarker][iElem]->SetCoord_CG(Coord);
14919  for (iNode = 0; iNode < nNode; iNode++)
14920  if (Coord[iNode] != NULL) delete[] Coord[iNode];
14921  if (Coord != NULL) delete[] Coord;
14922  }
14923 
14924  /*--- Center of gravity for edges ---*/
14925 
14926  for (iEdge = 0; iEdge < nEdge; iEdge++) {
14927  nNode = edge[iEdge]->GetnNodes();
14928  Coord = new su2double* [nNode];
14929 
14930  /*--- Store the coordinates for all the element nodes ---*/
14931 
14932  for (iNode = 0; iNode < nNode; iNode++) {
14933  edge_poin=edge[iEdge]->GetNode(iNode);
14934  Coord[iNode] = new su2double [nDim];
14935  for (iDim = 0; iDim < nDim; iDim++)
14936  Coord[iNode][iDim]=node[edge_poin]->GetCoord(iDim);
14937  }
14938 
14939  /*--- Compute the edge CG coordinates ---*/
14940 
14941  edge[iEdge]->SetCoord_CG(Coord);
14942 
14943  for (iNode = 0; iNode < nNode; iNode++)
14944  if (Coord[iNode] != NULL) delete[] Coord[iNode];
14945  if (Coord != NULL) delete[] Coord;
14946  }
14947 }
14948 
14949 void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) {
14950  unsigned short Neighbor_Node, iMarker, iNode, iNeighbor_Nodes, iDim;
14951  unsigned long Neighbor_Point, iVertex, iPoint, iElem;
14952  long iEdge;
14953  su2double Area, *NormalFace = NULL;
14954 
14955  /*--- Update values of faces of the edge ---*/
14956 
14957  if (action != ALLOCATE)
14958  for (iMarker = 0; iMarker < nMarker; iMarker++)
14959  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++)
14960  vertex[iMarker][iVertex]->SetZeroValues();
14961 
14962  su2double *Coord_Edge_CG = new su2double [nDim];
14963  su2double *Coord_Elem_CG = new su2double [nDim];
14964  su2double *Coord_Vertex = new su2double [nDim];
14965 
14966  /*--- Loop over all the markers ---*/
14967 
14968  for (iMarker = 0; iMarker < nMarker; iMarker++)
14969 
14970  /*--- Loop over all the boundary elements ---*/
14971 
14972  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++)
14973 
14974  /*--- Loop over all the nodes of the boundary ---*/
14975 
14976  for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) {
14977  iPoint = bound[iMarker][iElem]->GetNode(iNode);
14978  iVertex = node[iPoint]->GetVertex(iMarker);
14979 
14980  /*--- Loop over the neighbor nodes, there is a face for each one ---*/
14981 
14982  for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) {
14983  Neighbor_Node = bound[iMarker][iElem]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes);
14984  Neighbor_Point = bound[iMarker][iElem]->GetNode(Neighbor_Node);
14985 
14986  /*--- Shared edge by the Neighbor Point and the point ---*/
14987 
14988  iEdge = FindEdge(iPoint, Neighbor_Point);
14989  for (iDim = 0; iDim < nDim; iDim++) {
14990  Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim);
14991  Coord_Elem_CG[iDim] = bound[iMarker][iElem]->GetCG(iDim);
14992  Coord_Vertex[iDim] = node[iPoint]->GetCoord(iDim);
14993  }
14994  switch (nDim) {
14995  case 2:
14996 
14997  /*--- Store the 2D face ---*/
14998 
14999  if (iNode == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Vertex);
15000  if (iNode == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Vertex, Coord_Elem_CG);
15001  break;
15002  case 3:
15003 
15004  /*--- Store the 3D face ---*/
15005 
15006  if (iNeighbor_Nodes == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG, Coord_Vertex);
15007  if (iNeighbor_Nodes == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG, Coord_Vertex);
15008  break;
15009  }
15010  }
15011  }
15012 
15013  delete[] Coord_Edge_CG;
15014  delete[] Coord_Elem_CG;
15015  delete[] Coord_Vertex;
15016 
15017  /*--- Check if there is a normal with null area ---*/
15018 
15019  for (iMarker = 0; iMarker < nMarker; iMarker ++)
15020  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15021  NormalFace = vertex[iMarker][iVertex]->GetNormal();
15022  Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim];
15023  Area = sqrt(Area);
15024  if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS;
15025  }
15026 
15027 }
15028 
15030 
15031  for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){
15032  const unsigned short nNeigh = node[iPoint]->GetnPoint();
15033  const su2double* Coord_i = node[iPoint]->GetCoord();
15034 
15035  /*--- If using AD, computing the maximum grid length can generate
15036  * a lot of unnecessary overhead since we would store all computations
15037  * of each grid length, even though we only need the maximum value.
15038  * We solve that by finding the neighbor that's furthest away
15039  * (corresponding to the maximum distance) using passive calculations,
15040  * then set the max using the AD datatype. ---*/
15041 
15042  passivedouble passive_max_delta=0;
15043  unsigned short max_neighbor = 0;
15044  for (unsigned short iNeigh = 0; iNeigh < nNeigh; iNeigh++) {
15045 
15046  /*-- Calculate the cell-center to cell-center length ---*/
15047 
15048  const unsigned long jPoint = node[iPoint]->GetPoint(iNeigh);
15049  const su2double* Coord_j = node[jPoint]->GetCoord();
15050 
15051  passivedouble delta_aux = 0;
15052  for (unsigned short iDim = 0;iDim < nDim; iDim++){
15053  delta_aux += pow(SU2_TYPE::GetValue(Coord_j[iDim])-SU2_TYPE::GetValue(Coord_i[iDim]), 2.);
15054  }
15055 
15056  /*--- Only keep the maximum length ---*/
15057 
15058  if (delta_aux > passive_max_delta) {
15059  passive_max_delta = delta_aux;
15060  max_neighbor = iNeigh;
15061  }
15062  }
15063 
15064  /*--- Now that we know where the maximum distance is, repeat
15065  * calculation with the AD-friendly su2double datatype ---*/
15066 
15067  const unsigned long jPoint = node[iPoint]->GetPoint(max_neighbor);
15068  const su2double* Coord_j = node[jPoint]->GetCoord();
15069 
15070  su2double max_delta = 0;
15071  for (unsigned short iDim = 0;iDim < nDim; iDim++) {
15072  max_delta += pow((Coord_j[iDim]-Coord_i[iDim]), 2.);
15073  }
15074  max_delta = sqrt(max_delta);
15075 
15076  node[iPoint]->SetMaxLength(max_delta);
15077  }
15078 
15079  Set_MPI_MaxLength(config);
15080 }
15081 
15083 
15084  su2double epsilon = 1e-1;
15085 
15086  unsigned short nMarker_InterfaceBound = config->GetnMarker_InterfaceBound();
15087 
15088  if (nMarker_InterfaceBound != 0) {
15089 
15090  unsigned short iMarker, iDim, jMarker, pMarker = 0;
15091  unsigned long iVertex, iPoint, pVertex = 0, pPoint = 0, jVertex, jPoint, iPointGlobal, jPointGlobal, jVertex_, pPointGlobal = 0;
15092  su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global;
15093  int iProcessor, pProcessor = 0;
15094  unsigned long nLocalVertex_Interface = 0, MaxLocalVertex_Interface = 0;
15095  int nProcessor = size;
15096 
15097  unsigned long *Buffer_Send_nVertex = new unsigned long [1];
15098  unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor];
15099 
15100  if (rank == MASTER_NODE) cout << "Set Interface boundary conditions (if any)." << endl;
15101 
15102  /*--- Compute the number of vertex that have interfase boundary condition
15103  without including the ghost nodes ---*/
15104 
15105  nLocalVertex_Interface = 0;
15106  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
15107  if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY)
15108  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15109  iPoint = vertex[iMarker][iVertex]->GetNode();
15110  if (node[iPoint]->GetDomain()) nLocalVertex_Interface ++;
15111  }
15112 
15113  Buffer_Send_nVertex[0] = nLocalVertex_Interface;
15114 
15115  /*--- Send Interface vertex information --*/
15116 
15117 #ifndef HAVE_MPI
15118  MaxLocalVertex_Interface = nLocalVertex_Interface;
15119  Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0];
15120 #else
15121  SU2_MPI::Allreduce(&nLocalVertex_Interface, &MaxLocalVertex_Interface, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
15122  SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15123 #endif
15124 
15125  su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Interface*nDim];
15126  unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Interface];
15127  unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_Interface];
15128  unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_Interface];
15129  unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_Interface];
15130 
15131  su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Interface*nDim];
15132  unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Interface];
15133  unsigned long *Buffer_Receive_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_Interface];
15134  unsigned long *Buffer_Receive_Vertex = new unsigned long [nProcessor*MaxLocalVertex_Interface];
15135  unsigned long *Buffer_Receive_Marker = new unsigned long [nProcessor*MaxLocalVertex_Interface];
15136 
15137  unsigned long nBuffer_Coord = MaxLocalVertex_Interface*nDim;
15138  unsigned long nBuffer_Point = MaxLocalVertex_Interface;
15139  unsigned long nBuffer_GlobalIndex = MaxLocalVertex_Interface;
15140  unsigned long nBuffer_Vertex = MaxLocalVertex_Interface;
15141  unsigned long nBuffer_Marker = MaxLocalVertex_Interface;
15142 
15143  for (iVertex = 0; iVertex < MaxLocalVertex_Interface; iVertex++) {
15144  Buffer_Send_Point[iVertex] = 0;
15145  Buffer_Send_GlobalIndex[iVertex] = 0;
15146  Buffer_Send_Vertex[iVertex] = 0;
15147  Buffer_Send_Marker[iVertex] = 0;
15148  for (iDim = 0; iDim < nDim; iDim++)
15149  Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0;
15150  }
15151 
15152  /*--- Copy coordinates and point to the auxiliar vector --*/
15153 
15154  nLocalVertex_Interface = 0;
15155  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
15156  if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY)
15157  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15158  iPoint = vertex[iMarker][iVertex]->GetNode();
15159  iPointGlobal = node[iPoint]->GetGlobalIndex();
15160  if (node[iPoint]->GetDomain()) {
15161  Buffer_Send_Point[nLocalVertex_Interface] = iPoint;
15162  Buffer_Send_GlobalIndex[nLocalVertex_Interface] = iPointGlobal;
15163  Buffer_Send_Vertex[nLocalVertex_Interface] = iVertex;
15164  Buffer_Send_Marker[nLocalVertex_Interface] = iMarker;
15165  for (iDim = 0; iDim < nDim; iDim++)
15166  Buffer_Send_Coord[nLocalVertex_Interface*nDim+iDim] = node[iPoint]->GetCoord(iDim);
15167  nLocalVertex_Interface++;
15168  }
15169  }
15170 
15171 #ifndef HAVE_MPI
15172  for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++)
15173  Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord];
15174  for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++)
15175  Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point];
15176  for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++)
15177  Buffer_Receive_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex];
15178  for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++)
15179  Buffer_Receive_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex];
15180  for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++)
15181  Buffer_Receive_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker];
15182 #else
15183  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD);
15184  SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15185  SU2_MPI::Allgather(Buffer_Send_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15186  SU2_MPI::Allgather(Buffer_Send_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, Buffer_Receive_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15187  SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Receive_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15188 #endif
15189 
15190 
15191  /*--- Compute the closest point to a Near-Field boundary point ---*/
15192 
15193  maxdist_local = 0.0;
15194  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15195  if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) {
15196 
15197  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15198  iPoint = vertex[iMarker][iVertex]->GetNode();
15199  iPointGlobal = node[iPoint]->GetGlobalIndex();
15200 
15201  if (node[iPoint]->GetDomain()) {
15202 
15203  /*--- Coordinates of the boundary point ---*/
15204 
15205  Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0;
15206 
15207  /*--- Loop over all the boundaries to find the pair ---*/
15208  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++)
15209  for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) {
15210  jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Interface+jVertex];
15211  jPointGlobal = Buffer_Receive_GlobalIndex[iProcessor*MaxLocalVertex_Interface+jVertex];
15212  jVertex_ = Buffer_Receive_Vertex[iProcessor*MaxLocalVertex_Interface+jVertex];
15213  jMarker = Buffer_Receive_Marker[iProcessor*MaxLocalVertex_Interface+jVertex];
15214 
15215  if (jPointGlobal != iPointGlobal) {
15216 
15217  /*--- Compute the distance ---*/
15218 
15219  dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) {
15220  Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Interface+jVertex)*nDim+iDim];
15221  dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0);
15222  } dist = sqrt(dist);
15223 
15224  if (((dist < mindist) && (iProcessor != rank)) ||
15225  ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) {
15226  mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal;
15227  pVertex = jVertex_; pMarker = jMarker;
15228  if (dist == 0.0) break;
15229  }
15230  }
15231  }
15232 
15233  /*--- Store the value of the pair ---*/
15234 
15235  maxdist_local = max(maxdist_local, mindist);
15236  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor);
15237 
15238  if (mindist > epsilon) {
15239  cout.precision(10);
15240  cout << endl;
15241  cout << " Bad match for point " << iPoint << ".\tNearest";
15242  cout << " donor distance: " << scientific << mindist << ".";
15243  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iPointGlobal, pVertex, pMarker, pProcessor);
15244  maxdist_local = min(maxdist_local, 0.0);
15245  }
15246 
15247  }
15248  }
15249  }
15250  }
15251 
15252 #ifndef HAVE_MPI
15253  maxdist_global = maxdist_local;
15254 #else
15255  SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD);
15256 #endif
15257 
15258  if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl;
15259 
15260  delete[] Buffer_Send_Coord;
15261  delete[] Buffer_Send_Point;
15262 
15263  delete[] Buffer_Receive_Coord;
15264  delete[] Buffer_Receive_Point;
15265 
15266  delete[] Buffer_Send_nVertex;
15267  delete[] Buffer_Receive_nVertex;
15268 
15269  delete [] Buffer_Send_GlobalIndex;
15270  delete [] Buffer_Send_Vertex;
15271  delete [] Buffer_Send_Marker;
15272 
15273  delete [] Buffer_Receive_GlobalIndex;
15274  delete [] Buffer_Receive_Vertex;
15275  delete [] Buffer_Receive_Marker;
15276 
15277  }
15278 
15279 }
15280 
15282 
15283  su2double epsilon = 1e-1;
15284 
15285  unsigned short nMarker_NearFieldBound = config->GetnMarker_NearFieldBound();
15286 
15287  if (nMarker_NearFieldBound != 0) {
15288 
15289  unsigned short iMarker, iDim, jMarker, pMarker = 0;
15290  unsigned long iVertex, iPoint, pVertex = 0, pPoint = 0, jVertex, jPoint, iPointGlobal, jPointGlobal, jVertex_, pPointGlobal = 0;
15291  su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global;
15292  int iProcessor, pProcessor = 0;
15293  unsigned long nLocalVertex_NearField = 0, MaxLocalVertex_NearField = 0;
15294  int nProcessor = size;
15295 
15296  unsigned long *Buffer_Send_nVertex = new unsigned long [1];
15297  unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor];
15298 
15299  if (rank == MASTER_NODE) cout << "Set NearField boundary conditions (if any)." << endl;
15300 
15301  /*--- Compute the number of vertex that have interfase boundary condition
15302  without including the ghost nodes ---*/
15303 
15304  nLocalVertex_NearField = 0;
15305  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
15306  if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY)
15307  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15308  iPoint = vertex[iMarker][iVertex]->GetNode();
15309  if (node[iPoint]->GetDomain()) nLocalVertex_NearField ++;
15310  }
15311 
15312  Buffer_Send_nVertex[0] = nLocalVertex_NearField;
15313 
15314  /*--- Send NearField vertex information --*/
15315 
15316 #ifndef HAVE_MPI
15317  MaxLocalVertex_NearField = nLocalVertex_NearField;
15318  Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0];
15319 #else
15320  SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
15321  SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15322 #endif
15323 
15324  su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NearField*nDim];
15325  unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_NearField];
15326  unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_NearField];
15327  unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_NearField];
15328  unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_NearField];
15329 
15330  su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NearField*nDim];
15331  unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_NearField];
15332  unsigned long *Buffer_Receive_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_NearField];
15333  unsigned long *Buffer_Receive_Vertex = new unsigned long [nProcessor*MaxLocalVertex_NearField];
15334  unsigned long *Buffer_Receive_Marker = new unsigned long [nProcessor*MaxLocalVertex_NearField];
15335 
15336  unsigned long nBuffer_Coord = MaxLocalVertex_NearField*nDim;
15337  unsigned long nBuffer_Point = MaxLocalVertex_NearField;
15338  unsigned long nBuffer_GlobalIndex = MaxLocalVertex_NearField;
15339  unsigned long nBuffer_Vertex = MaxLocalVertex_NearField;
15340  unsigned long nBuffer_Marker = MaxLocalVertex_NearField;
15341 
15342  for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) {
15343  Buffer_Send_Point[iVertex] = 0;
15344  Buffer_Send_GlobalIndex[iVertex] = 0;
15345  Buffer_Send_Vertex[iVertex] = 0;
15346  Buffer_Send_Marker[iVertex] = 0;
15347  for (iDim = 0; iDim < nDim; iDim++)
15348  Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0;
15349  }
15350 
15351  /*--- Copy coordinates and point to the auxiliar vector --*/
15352 
15353  nLocalVertex_NearField = 0;
15354  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
15355  if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY)
15356  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15357  iPoint = vertex[iMarker][iVertex]->GetNode();
15358  iPointGlobal = node[iPoint]->GetGlobalIndex();
15359  if (node[iPoint]->GetDomain()) {
15360  Buffer_Send_Point[nLocalVertex_NearField] = iPoint;
15361  Buffer_Send_GlobalIndex[nLocalVertex_NearField] = iPointGlobal;
15362  Buffer_Send_Vertex[nLocalVertex_NearField] = iVertex;
15363  Buffer_Send_Marker[nLocalVertex_NearField] = iMarker;
15364  for (iDim = 0; iDim < nDim; iDim++)
15365  Buffer_Send_Coord[nLocalVertex_NearField*nDim+iDim] = node[iPoint]->GetCoord(iDim);
15366  nLocalVertex_NearField++;
15367  }
15368  }
15369 
15370 #ifndef HAVE_MPI
15371  for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++)
15372  Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord];
15373  for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++)
15374  Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point];
15375  for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++)
15376  Buffer_Receive_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex];
15377  for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++)
15378  Buffer_Receive_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex];
15379  for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++)
15380  Buffer_Receive_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker];
15381 #else
15382  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD);
15383  SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15384  SU2_MPI::Allgather(Buffer_Send_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15385  SU2_MPI::Allgather(Buffer_Send_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, Buffer_Receive_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15386  SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Receive_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15387 #endif
15388 
15389 
15390  /*--- Compute the closest point to a Near-Field boundary point ---*/
15391 
15392  maxdist_local = 0.0;
15393  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15394  if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) {
15395 
15396  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15397  iPoint = vertex[iMarker][iVertex]->GetNode();
15398  iPointGlobal = node[iPoint]->GetGlobalIndex();
15399 
15400  if (node[iPoint]->GetDomain()) {
15401 
15402  /*--- Coordinates of the boundary point ---*/
15403 
15404  Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0;
15405 
15406  /*--- Loop over all the boundaries to find the pair ---*/
15407  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++)
15408  for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) {
15409  jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_NearField+jVertex];
15410  jPointGlobal = Buffer_Receive_GlobalIndex[iProcessor*MaxLocalVertex_NearField+jVertex];
15411  jVertex_ = Buffer_Receive_Vertex[iProcessor*MaxLocalVertex_NearField+jVertex];
15412  jMarker = Buffer_Receive_Marker[iProcessor*MaxLocalVertex_NearField+jVertex];
15413 
15414  if (jPointGlobal != iPointGlobal) {
15415 
15416  /*--- Compute the distance ---*/
15417 
15418  dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) {
15419  Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NearField+jVertex)*nDim+iDim];
15420  dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0);
15421  } dist = sqrt(dist);
15422 
15423  if (((dist < mindist) && (iProcessor != rank)) ||
15424  ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) {
15425  mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal;
15426  pVertex = jVertex_; pMarker = jMarker;
15427  if (dist == 0.0) break;
15428  }
15429  }
15430  }
15431 
15432  /*--- Store the value of the pair ---*/
15433 
15434  maxdist_local = max(maxdist_local, mindist);
15435  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor);
15436 
15437  if (mindist > epsilon) {
15438  cout.precision(10);
15439  cout << endl;
15440  cout << " Bad match for point " << iPoint << ".\tNearest";
15441  cout << " donor distance: " << scientific << mindist << ".";
15442  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iPointGlobal, pVertex, pMarker, pProcessor);
15443  maxdist_local = min(maxdist_local, 0.0);
15444  }
15445 
15446  }
15447  }
15448  }
15449  }
15450 
15451 #ifndef HAVE_MPI
15452  maxdist_global = maxdist_local;
15453 #else
15454  SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD);
15455 #endif
15456 
15457  if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl;
15458 
15459  delete[] Buffer_Send_Coord;
15460  delete[] Buffer_Send_Point;
15461 
15462  delete[] Buffer_Receive_Coord;
15463  delete[] Buffer_Receive_Point;
15464 
15465  delete[] Buffer_Send_nVertex;
15466  delete[] Buffer_Receive_nVertex;
15467 
15468  delete [] Buffer_Send_GlobalIndex;
15469  delete [] Buffer_Send_Vertex;
15470  delete [] Buffer_Send_Marker;
15471 
15472  delete [] Buffer_Receive_GlobalIndex;
15473  delete [] Buffer_Receive_Vertex;
15474  delete [] Buffer_Receive_Marker;
15475 
15476  }
15477 
15478 }
15479 
15481 
15482  su2double epsilon = 1e-1;
15483 
15484  unsigned short nMarker_ActDiskInlet = config->GetnMarker_ActDiskInlet();
15485 
15486  if (nMarker_ActDiskInlet != 0) {
15487 
15488  unsigned short iMarker, iDim;
15489  unsigned long iVertex, iPoint, iPointGlobal, pPoint = 0, pPointGlobal = 0, pVertex = 0, pMarker = 0, jVertex, jVertex_, jPoint, jPointGlobal, jMarker;
15490  su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local = 0.0, maxdist_global = 0.0;
15491  int iProcessor, pProcessor = 0;
15492  unsigned long nLocalVertex_ActDisk = 0, MaxLocalVertex_ActDisk = 0;
15493  int nProcessor = size;
15494  unsigned short Beneficiary = 0, Donor = 0, iBC;
15495  bool Perimeter;
15496 
15497  for (iBC = 0; iBC < 2; iBC++) {
15498 
15499  if (iBC == 0) { Beneficiary = ACTDISK_INLET; Donor = ACTDISK_OUTLET; }
15500  if (iBC == 1) { Beneficiary = ACTDISK_OUTLET; Donor = ACTDISK_INLET; }
15501 
15502  unsigned long *Buffer_Send_nVertex = new unsigned long [1];
15503  unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor];
15504 
15505  if ((iBC == 0) && (rank == MASTER_NODE)) cout << "Set Actuator Disk inlet boundary conditions." << endl;
15506  if ((iBC == 1) && (rank == MASTER_NODE)) cout << "Set Actuator Disk outlet boundary conditions." << endl;
15507 
15508  /*--- Compute the number of vertex that have an actuator disk outlet boundary condition
15509  without including the ghost nodes ---*/
15510 
15511  nLocalVertex_ActDisk = 0;
15512  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15513  if (config->GetMarker_All_KindBC(iMarker) == Donor) {
15514  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15515  iPoint = vertex[iMarker][iVertex]->GetNode();
15516  if (node[iPoint]->GetDomain()) nLocalVertex_ActDisk ++;
15517  }
15518  }
15519  }
15520 
15521  Buffer_Send_nVertex[0] = nLocalVertex_ActDisk;
15522 
15523  /*--- Send actuator disk vertex information --*/
15524 
15525 #ifndef HAVE_MPI
15526  MaxLocalVertex_ActDisk = nLocalVertex_ActDisk;
15527  Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0];
15528 #else
15529  SU2_MPI::Allreduce(&nLocalVertex_ActDisk, &MaxLocalVertex_ActDisk, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
15530  SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15531 #endif
15532 
15533  /*--- Array dimensionalization --*/
15534 
15535  su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_ActDisk*nDim];
15536  unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_ActDisk];
15537  unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_ActDisk];
15538  unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_ActDisk];
15539  unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_ActDisk];
15540 
15541  su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_ActDisk*nDim];
15542  unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_ActDisk];
15543  unsigned long *Buffer_Receive_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_ActDisk];
15544  unsigned long *Buffer_Receive_Vertex = new unsigned long [nProcessor*MaxLocalVertex_ActDisk];
15545  unsigned long *Buffer_Receive_Marker = new unsigned long [nProcessor*MaxLocalVertex_ActDisk];
15546 
15547  unsigned long nBuffer_Coord = MaxLocalVertex_ActDisk*nDim;
15548  unsigned long nBuffer_Point = MaxLocalVertex_ActDisk;
15549  unsigned long nBuffer_GlobalIndex = MaxLocalVertex_ActDisk;
15550  unsigned long nBuffer_Vertex = MaxLocalVertex_ActDisk;
15551  unsigned long nBuffer_Marker = MaxLocalVertex_ActDisk;
15552 
15553  for (iVertex = 0; iVertex < MaxLocalVertex_ActDisk; iVertex++) {
15554  Buffer_Send_Point[iVertex] = 0;
15555  Buffer_Send_GlobalIndex[iVertex] = 0;
15556  Buffer_Send_Vertex[iVertex] = 0;
15557  Buffer_Send_Marker[iVertex] = 0;
15558  for (iDim = 0; iDim < nDim; iDim++)
15559  Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0;
15560  }
15561 
15562  /*--- Copy coordinates and point to the auxiliar vector --*/
15563 
15564  nLocalVertex_ActDisk = 0;
15565  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15566  if (config->GetMarker_All_KindBC(iMarker) == Donor) {
15567  for (iVertex = 0; iVertex < GetnVertex(iMarker); iVertex++) {
15568  iPoint = vertex[iMarker][iVertex]->GetNode();
15569  iPointGlobal = node[iPoint]->GetGlobalIndex();
15570  if (node[iPoint]->GetDomain()) {
15571  Buffer_Send_Point[nLocalVertex_ActDisk] = iPoint;
15572  Buffer_Send_GlobalIndex[nLocalVertex_ActDisk] = iPointGlobal;
15573  Buffer_Send_Vertex[nLocalVertex_ActDisk] = iVertex;
15574  Buffer_Send_Marker[nLocalVertex_ActDisk] = iMarker;
15575  for (iDim = 0; iDim < nDim; iDim++)
15576  Buffer_Send_Coord[nLocalVertex_ActDisk*nDim+iDim] = node[iPoint]->GetCoord(iDim);
15577  nLocalVertex_ActDisk++;
15578  }
15579  }
15580  }
15581  }
15582 
15583 #ifndef HAVE_MPI
15584  for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++)
15585  Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord];
15586  for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++)
15587  Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point];
15588  for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++)
15589  Buffer_Receive_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex];
15590  for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++)
15591  Buffer_Receive_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex];
15592  for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++)
15593  Buffer_Receive_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker];
15594 
15595 #else
15596  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD);
15597  SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15598  SU2_MPI::Allgather(Buffer_Send_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15599  SU2_MPI::Allgather(Buffer_Send_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, Buffer_Receive_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15600  SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Receive_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15601 #endif
15602 
15603  /*--- Compute the closest point to an actuator disk inlet point ---*/
15604 
15605  maxdist_local = 0.0;
15606 
15607  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15608  if (config->GetMarker_All_KindBC(iMarker) == Beneficiary) {
15609 
15610  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15611  iPoint = vertex[iMarker][iVertex]->GetNode();
15612  iPointGlobal = node[iPoint]->GetGlobalIndex();
15613 
15614 
15615  if (node[iPoint]->GetDomain()) {
15616 
15617  /*--- Coordinates of the boundary point ---*/
15618 
15619  Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0;
15620 
15621  /*--- Loop over all the boundaries to find the pair ---*/
15622 
15623  Perimeter = false;
15624 
15625  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) {
15626  for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) {
15627  jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_ActDisk+jVertex];
15628  jPointGlobal = Buffer_Receive_GlobalIndex[iProcessor*MaxLocalVertex_ActDisk+jVertex];
15629  jVertex_ = Buffer_Receive_Vertex[iProcessor*MaxLocalVertex_ActDisk+jVertex];
15630  jMarker = Buffer_Receive_Marker[iProcessor*MaxLocalVertex_ActDisk+jVertex];
15631 
15632  // if (jPointGlobal != iPointGlobal) {
15633  // ActDisk_Perimeter
15634 
15635  /*--- Compute the distance ---*/
15636 
15637  dist = 0.0;
15638  for (iDim = 0; iDim < nDim; iDim++) {
15639  Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_ActDisk+jVertex)*nDim+iDim];
15640  dist += pow(Coord_j[iDim]-Coord_i[iDim], 2.0);
15641  }
15642  dist = sqrt(dist);
15643 
15644  if (dist < mindist) {
15645  mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal;
15646  pVertex = jVertex_; pMarker = jMarker;
15647  if (dist == 0.0) break;
15648  }
15649 
15650 // }
15651 // else { Perimeter = true; mindist = 0.0; dist = 0.0; break; }
15652  }
15653  }
15654 
15655  /*--- Store the value of the pair ---*/
15656 
15657  maxdist_local = max(maxdist_local, mindist);
15658  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor);
15659  vertex[iMarker][iVertex]->SetActDisk_Perimeter(Perimeter);
15660 
15661  if (mindist > epsilon) {
15662  cout.precision(10);
15663  cout << endl;
15664  cout << " Bad match for point " << iPoint << ".\tNearest";
15665  cout << " donor distance: " << scientific << mindist << ".";
15666  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iPointGlobal, pVertex, pMarker, pProcessor);
15667  maxdist_local = min(maxdist_local, 0.0);
15668  }
15669 
15670  }
15671  }
15672 
15673  }
15674  }
15675 
15676 #ifndef HAVE_MPI
15677  maxdist_global = maxdist_local;
15678 #else
15679  SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD);
15680 #endif
15681 
15682  if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl;
15683 
15684  delete[] Buffer_Send_Coord;
15685  delete[] Buffer_Send_Point;
15686 
15687  delete[] Buffer_Receive_Coord;
15688  delete[] Buffer_Receive_Point;
15689 
15690  delete[] Buffer_Send_nVertex;
15691  delete[] Buffer_Receive_nVertex;
15692 
15693  delete [] Buffer_Send_GlobalIndex;
15694  delete [] Buffer_Send_Vertex;
15695  delete [] Buffer_Send_Marker;
15696 
15697  delete [] Buffer_Receive_GlobalIndex;
15698  delete [] Buffer_Receive_Vertex;
15699  delete [] Buffer_Receive_Marker;
15700 
15701  }
15702  }
15703 
15704 }
15705 
15706 void CPhysicalGeometry::MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor,
15707  unsigned short val_iZone, unsigned short val_nZone) {
15708 
15709 #ifndef HAVE_MPI
15710 
15711  unsigned short iMarker, jMarker;
15712  unsigned long iVertex, iPoint, jVertex, jPoint = 0, pPoint = 0, pGlobalPoint = 0;
15713  su2double *Coord_i, *Coord_j, dist = 0.0, mindist, maxdist;
15714 
15715 // if (val_iZone == ZONE_0) cout << "Set zone boundary conditions (if any)." << endl;
15716 
15717  maxdist = 0.0;
15718  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15719  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15720  iPoint = vertex[iMarker][iVertex]->GetNode();
15721  Coord_i = node[iPoint]->GetCoord();
15722 
15723  mindist = 1E6;
15724  for (jMarker = 0; jMarker < config_donor->GetnMarker_All(); jMarker++)
15725  for (jVertex = 0; jVertex < geometry_donor->GetnVertex(jMarker); jVertex++) {
15726  jPoint = geometry_donor->vertex[jMarker][jVertex]->GetNode();
15727  Coord_j = geometry_donor->node[jPoint]->GetCoord();
15728  if (nDim == 2) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0));
15729  if (nDim == 3) dist = sqrt(pow(Coord_j[0]-Coord_i[0],2.0) + pow(Coord_j[1]-Coord_i[1],2.0) + pow(Coord_j[2]-Coord_i[2],2.0));
15730 // if (dist < mindist) { mindist = dist; pPoint = jPoint; pGlobalPoint = node[jPoint]->GetGlobalIndex();}
15731  if (dist < mindist) { mindist = dist; pPoint = jPoint; pGlobalPoint = geometry_donor->node[jPoint]->GetGlobalIndex();}
15732  }
15733 
15734  maxdist = max(maxdist, mindist);
15735  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE, pGlobalPoint);
15736 
15737  }
15738  }
15739 
15740 #else
15741 
15742  unsigned short iMarker, iDim;
15743  unsigned long iVertex, iPoint, pPoint = 0, jVertex, jPoint, jGlobalPoint = 0, pGlobalPoint = 0;
15744  su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist;
15745  int iProcessor, pProcessor = 0;
15746  unsigned long nLocalVertex_Zone = 0, nGlobalVertex_Zone = 0, MaxLocalVertex_Zone = 0;
15747  int nProcessor = size;
15748 
15749  unsigned long *Buffer_Send_nVertex = new unsigned long [1];
15750  unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor];
15751 
15752 // if (val_iZone == ZONE_0 && rank == MASTER_NODE) cout << "Set zone boundary conditions (if any)." << endl;
15753 
15754  nLocalVertex_Zone = 0;
15755  for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++)
15756  for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) {
15757  iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode();
15758  if (geometry_donor->node[iPoint]->GetDomain()) nLocalVertex_Zone ++;
15759  }
15760 
15761  Buffer_Send_nVertex[0] = nLocalVertex_Zone;
15762 
15763  /*--- Send Interface vertex information --*/
15764 
15765  SU2_MPI::Allreduce(&nLocalVertex_Zone, &nGlobalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
15766  SU2_MPI::Allreduce(&nLocalVertex_Zone, &MaxLocalVertex_Zone, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD);
15767  SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15768 
15769  su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Zone*nDim];
15770  unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Zone];
15771  unsigned long *Buffer_Send_GlobalPoint = new unsigned long [MaxLocalVertex_Zone];
15772 
15773  su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_Zone*nDim];
15774  unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_Zone];
15775  unsigned long *Buffer_Receive_GlobalPoint = new unsigned long [nProcessor*MaxLocalVertex_Zone];
15776 
15777  unsigned long nBuffer_Coord = MaxLocalVertex_Zone*nDim;
15778  unsigned long nBuffer_Point = MaxLocalVertex_Zone;
15779 
15780 
15781  for (iVertex = 0; iVertex < MaxLocalVertex_Zone; iVertex++) {
15782  Buffer_Send_Point[iVertex] = 0;
15783  Buffer_Send_GlobalPoint[iVertex] = 0;
15784  for (iDim = 0; iDim < nDim; iDim++)
15785  Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0;
15786  }
15787 
15788  /*--- Copy coordinates and point to the auxiliar vector --*/
15789  nLocalVertex_Zone = 0;
15790  for (iMarker = 0; iMarker < config_donor->GetnMarker_All(); iMarker++)
15791  for (iVertex = 0; iVertex < geometry_donor->GetnVertex(iMarker); iVertex++) {
15792  iPoint = geometry_donor->vertex[iMarker][iVertex]->GetNode();
15793  if (geometry_donor->node[iPoint]->GetDomain()) {
15794  Buffer_Send_Point[nLocalVertex_Zone] = iPoint;
15795  Buffer_Send_GlobalPoint[nLocalVertex_Zone] = geometry_donor->node[iPoint]->GetGlobalIndex();
15796  for (iDim = 0; iDim < nDim; iDim++)
15797  Buffer_Send_Coord[nLocalVertex_Zone*nDim+iDim] = geometry_donor->node[iPoint]->GetCoord(iDim);
15798  nLocalVertex_Zone++;
15799  }
15800  }
15801 
15802  SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD);
15803  SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15804  SU2_MPI::Allgather(Buffer_Send_GlobalPoint, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalPoint, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD);
15805 
15806  /*--- Compute the closest point to a Near-Field boundary point ---*/
15807  maxdist = 0.0;
15808  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
15809  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
15810  iPoint = vertex[iMarker][iVertex]->GetNode();
15811 
15812  if (node[iPoint]->GetDomain()) {
15813 
15814  /*--- Coordinates of the boundary point ---*/
15815  Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0;
15816 
15817  /*--- Loop over all the boundaries to find the pair ---*/
15818  for (iProcessor = 0; iProcessor < nProcessor; iProcessor++)
15819  for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) {
15820  jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_Zone+jVertex];
15821  jGlobalPoint = Buffer_Receive_GlobalPoint[iProcessor*MaxLocalVertex_Zone+jVertex];
15822 
15823  /*--- Compute the distance ---*/
15824  dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) {
15825  Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_Zone+jVertex)*nDim+iDim];
15826  dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0);
15827  } dist = sqrt(dist);
15828 
15829  if (((dist < mindist) && (iProcessor != rank)) ||
15830  ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) {
15831  mindist = dist; pProcessor = iProcessor; pPoint = jPoint;
15832  pGlobalPoint = jGlobalPoint;
15833  }
15834  }
15835 
15836  /*--- Store the value of the pair ---*/
15837  maxdist = max(maxdist, mindist);
15838  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pProcessor, pGlobalPoint);
15839 
15840 
15841  }
15842  }
15843  }
15844 
15845  delete[] Buffer_Send_Coord;
15846  delete[] Buffer_Send_Point;
15847  delete[] Buffer_Send_GlobalPoint;
15848 
15849  delete[] Buffer_Receive_Coord;
15850  delete[] Buffer_Receive_Point;
15851  delete[] Buffer_Receive_GlobalPoint;
15852 
15853  delete[] Buffer_Send_nVertex;
15854  delete[] Buffer_Receive_nVertex;
15855 
15856 #endif
15857 
15858 }
15859 
15860 
15861 void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) {
15862  unsigned long face_iPoint = 0, face_jPoint = 0, iPoint, iElem;
15863  long iEdge;
15864  unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim;
15865  su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint, *Coord_FacejPoint, Area,
15866  Volume, DomainVolume, my_DomainVolume, *NormalFace = NULL;
15867  bool change_face_orientation;
15868 
15869  /*--- Update values of faces of the edge ---*/
15870  if (action != ALLOCATE) {
15871  for (iEdge = 0; iEdge < (long)nEdge; iEdge++)
15872  edge[iEdge]->SetZeroValues();
15873  for (iPoint = 0; iPoint < nPoint; iPoint++)
15874  node[iPoint]->SetVolume (0.0);
15875  }
15876 
15877  Coord_Edge_CG = new su2double [nDim];
15878  Coord_FaceElem_CG = new su2double [nDim];
15879  Coord_Elem_CG = new su2double [nDim];
15880  Coord_FaceiPoint = new su2double [nDim];
15881  Coord_FacejPoint = new su2double [nDim];
15882 
15883  my_DomainVolume = 0.0;
15884  for (iElem = 0; iElem < nElem; iElem++)
15885  for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) {
15886 
15887  /*--- In 2D all the faces have only one edge ---*/
15888  if (nDim == 2) nEdgesFace = 1;
15889  /*--- In 3D the number of edges per face is the same as the number of point per face ---*/
15890  if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace);
15891 
15892  /*-- Loop over the edges of a face ---*/
15893  for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) {
15894 
15895  /*--- In 2D only one edge (two points) per edge ---*/
15896  if (nDim == 2) {
15897  face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0));
15898  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1));
15899  }
15900 
15901  /*--- In 3D there are several edges in each face ---*/
15902  if (nDim == 3) {
15903  face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace));
15904  if (iEdgesFace != nEdgesFace-1)
15905  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1));
15906  else
15907  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0));
15908  }
15909 
15910  /*--- We define a direction (from the smalest index to the greatest) --*/
15911  change_face_orientation = false;
15912  if (face_iPoint > face_jPoint) change_face_orientation = true;
15913  iEdge = FindEdge(face_iPoint, face_jPoint);
15914 
15915  for (iDim = 0; iDim < nDim; iDim++) {
15916  Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim);
15917  Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim);
15918  Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim);
15919  Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim);
15920  Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim);
15921  }
15922 
15923  switch (nDim) {
15924  case 2:
15925  /*--- Two dimensional problem ---*/
15926  if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG);
15927  else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG);
15928  Area = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_Elem_CG);
15929  node[face_iPoint]->AddVolume(Area); my_DomainVolume +=Area;
15930  Area = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_Elem_CG);
15931  node[face_jPoint]->AddVolume(Area); my_DomainVolume +=Area;
15932  break;
15933  case 3:
15934  /*--- Three dimensional problem ---*/
15935  if (change_face_orientation) edge[iEdge]->SetNodes_Coord(Coord_FaceElem_CG, Coord_Edge_CG, Coord_Elem_CG);
15936  else edge[iEdge]->SetNodes_Coord(Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG);
15937  Volume = edge[iEdge]->GetVolume(Coord_FaceiPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG);
15938  node[face_iPoint]->AddVolume(Volume); my_DomainVolume +=Volume;
15939  Volume = edge[iEdge]->GetVolume(Coord_FacejPoint, Coord_Edge_CG, Coord_FaceElem_CG, Coord_Elem_CG);
15940  node[face_jPoint]->AddVolume(Volume); my_DomainVolume +=Volume;
15941  break;
15942  }
15943  }
15944  }
15945 
15946  /*--- Check if there is a normal with null area ---*/
15947  for (iEdge = 0; iEdge < (long)nEdge; iEdge++) {
15948  NormalFace = edge[iEdge]->GetNormal();
15949  Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim];
15950  Area = sqrt(Area);
15951  if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS;
15952  }
15953 
15954 
15955 #ifdef HAVE_MPI
15956  SU2_MPI::Allreduce(&my_DomainVolume, &DomainVolume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
15957 #else
15958  DomainVolume = my_DomainVolume;
15959 #endif
15960 
15961  if ((rank == MASTER_NODE) && (action == ALLOCATE)) {
15962  if (nDim == 2) cout <<"Area of the computational grid: "<< DomainVolume <<"."<< endl;
15963  if (nDim == 3) cout <<"Volume of the computational grid: "<< DomainVolume <<"."<< endl;
15964  }
15965 
15966  config->SetDomainVolume(DomainVolume);
15967 
15968  delete[] Coord_Edge_CG;
15969  delete[] Coord_FaceElem_CG;
15970  delete[] Coord_Elem_CG;
15971  delete[] Coord_FaceiPoint;
15972  delete[] Coord_FacejPoint;
15973 }
15974 
15975 void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) {
15976 
15977  /*--- This routine is only meant for visualization in serial currently ---*/
15978 #ifndef HAVE_MPI
15979 
15980  unsigned long face_iPoint = 0, face_jPoint = 0, iElem, iPoint_Viz;
15981  long iEdge;
15982  unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim;
15983  su2double *Coord_Edge_CG, *Coord_FaceElem_CG, *Coord_Elem_CG, *Coord_FaceiPoint,
15984  *Coord_FacejPoint;
15985  int counter = 0;
15986  char cstr[MAX_STRING_SIZE], buffer[50];
15987  ofstream Tecplot_File;
15988  string mesh_filename;
15989  vector<su2double> X, Y, Z, X_n, Y_n, Z_n;
15990  su2double r1[3], r2[3], CrossProduct[3];
15991 
15992  /*--- Access the point number for control volume we want to vizualize ---*/
15993 
15994  iPoint_Viz = config->GetVisualize_CV();
15995 
15996  /*--- Allocate some structures for building the dual CVs ---*/
15997 
15998  Coord_Edge_CG = new su2double [nDim];
15999  Coord_FaceElem_CG = new su2double [nDim];
16000  Coord_Elem_CG = new su2double [nDim];
16001  Coord_FaceiPoint = new su2double [nDim];
16002  Coord_FacejPoint = new su2double [nDim];
16003 
16004  /*--- Loop over each face of each element ---*/
16005 
16006  CrossProduct[0] = 0.0; CrossProduct[1] = 0.0; CrossProduct[2] = 0.0;
16007 
16008  for (iElem = 0; iElem < nElem; iElem++) {
16009 
16010  for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) {
16011 
16012  /*--- In 2D all the faces have only one edge ---*/
16013  if (nDim == 2) nEdgesFace = 1;
16014  /*--- In 3D the number of edges per face is the same as the number of point per face ---*/
16015  if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace);
16016 
16017  /*-- Loop over the edges of a face ---*/
16018  for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) {
16019 
16020  /*--- In 2D only one edge (two points) per edge ---*/
16021  if (nDim == 2) {
16022  face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0));
16023  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1));
16024  }
16025 
16026  /*--- In 3D there are several edges in each face ---*/
16027  if (nDim == 3) {
16028  face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace));
16029  if (iEdgesFace != nEdgesFace-1)
16030  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace+1));
16031  else
16032  face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0));
16033  }
16034 
16035  /*--- We define a direction (from the smallest index to the greatest) --*/
16036  iEdge = FindEdge(face_iPoint, face_jPoint);
16037 
16038  for (iDim = 0; iDim < nDim; iDim++) {
16039  Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim);
16040  Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim);
16041  Coord_FaceElem_CG[iDim] = elem[iElem]->GetFaceCG(iFace, iDim);
16042  Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim);
16043  Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim);
16044  }
16045 
16046  /*--- Print out the coordinates for a set of triangles making
16047  up a single dual control volume for visualization. ---*/
16048 
16049  if (face_iPoint == iPoint_Viz || face_jPoint == iPoint_Viz) {
16050 
16051  if (nDim == 2) {
16052  X.push_back(Coord_Elem_CG[0]); X.push_back(Coord_Edge_CG[0]);
16053  Y.push_back(Coord_Elem_CG[1]); Y.push_back(Coord_Edge_CG[1]);
16054  } else if (nDim == 3) {
16055  X.push_back(Coord_FaceElem_CG[0]); X.push_back(Coord_Edge_CG[0]); X.push_back(Coord_Elem_CG[0]);
16056  Y.push_back(Coord_FaceElem_CG[1]); Y.push_back(Coord_Edge_CG[1]); Y.push_back(Coord_Elem_CG[1]);
16057  Z.push_back(Coord_FaceElem_CG[2]); Z.push_back(Coord_Edge_CG[2]); Z.push_back(Coord_Elem_CG[2]);
16058 
16059  for (iDim = 0; iDim < nDim; iDim++) {
16060  r1[iDim] = Coord_FaceElem_CG[iDim]-Coord_Elem_CG[iDim];
16061  r2[iDim] = Coord_Edge_CG[iDim]-Coord_Elem_CG[iDim];
16062  }
16063  CrossProduct[0] += 0.5*(r1[1]*r2[2] - r1[2]*r2[1]);
16064  CrossProduct[1] += 0.5*(r1[2]*r2[0] - r1[0]*r2[2]);
16065  CrossProduct[2] += 0.5*(r1[0]*r2[1] - r1[1]*r2[0]);
16066  }
16067  counter++;
16068  }
16069  }
16070  }
16071  }
16072 
16073  /*--- Write a Tecplot file to visualize the CV ---*/
16074 
16075  strcpy(cstr,"dual_cv");
16076  SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iPoint_Viz));
16077  strcat(cstr, buffer);
16078 
16079  Tecplot_File.open(cstr, ios::out);
16080  Tecplot_File << "TITLE= \"Visualization of the control volume\"" << endl;
16081 
16082  if (nDim == 2) {
16083  Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl;
16084  Tecplot_File << "ZONE NODES= "<< counter*2 <<", ELEMENTS= ";
16085  Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl;
16086  } if (nDim == 3) {
16087  Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl;
16088  Tecplot_File << "ZONE NODES= "<< counter*3 <<", ELEMENTS= ";
16089  Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl;
16090  }
16091 
16092  /*--- Write coordinates for the nodes in the order that they were found
16093  for each of the edges/triangles making up a dual control volume. ---*/
16094 
16095  for (vector<su2double>::size_type i = 0; i != X.size(); i++) {
16096  Tecplot_File << X[i] << "\t" << Y[i];
16097  if (nDim == 3) Tecplot_File << "\t" << Z[i];
16098  Tecplot_File << "\n";
16099  }
16100 
16101  /*--- Create a new connectivity table in the order the faces were found ---*/
16102 
16103  int j;
16104  for (int i= 0; i < counter; i++) {
16105  if (nDim == 2) {
16106  j = i*2;
16107  Tecplot_File << j+1 <<"\t"<<j+2 <<"\t"<<j+2 <<"\t"<<j+2 << endl;
16108  } if (nDim == 3) {
16109  j = i*3;
16110  Tecplot_File << j+1 <<"\t"<<j+2 <<"\t"<<j+3 <<"\t"<<j+3 <<"\t";
16111  Tecplot_File << j+3<<"\t" <<j+3 <<"\t"<<j+3 <<"\t"<<j+3 << endl;
16112  }
16113  }
16114 
16115  Tecplot_File.close();
16116  X.clear();
16117  Y.clear();
16118  Z.clear();
16119 
16120  delete[] Coord_Edge_CG;
16121  delete[] Coord_FaceElem_CG;
16122  delete[] Coord_Elem_CG;
16123  delete[] Coord_FaceiPoint;
16124  delete[] Coord_FacejPoint;
16125 
16126 #endif
16127 
16128 }
16129 
16130 void CPhysicalGeometry::SetMeshFile (CConfig *config, string val_mesh_out_filename) {
16131  unsigned long iElem, iPoint, iElem_Bound;
16132  unsigned short iMarker, iNodes, iDim;
16133  unsigned short iPeriodic, nPeriodic = 0;
16134  ofstream output_file;
16135  string Grid_Marker;
16136  char *cstr;
16137  su2double *center, *angles, *transl;
16138 
16139  cstr = new char [val_mesh_out_filename.size()+1];
16140  strcpy (cstr, val_mesh_out_filename.c_str());
16141 
16142  /*--- Open .su2 grid file ---*/
16143 
16144  output_file.precision(15);
16145  output_file.open(cstr, ios::out);
16146 
16147  /*--- Write dimension, number of elements and number of points ---*/
16148 
16149  output_file << "NDIME= " << nDim << endl;
16150  output_file << "NELEM= " << nElem << endl;
16151  for (iElem = 0; iElem < nElem; iElem++) {
16152  output_file << elem[iElem]->GetVTK_Type();
16153  for (iNodes = 0; iNodes < elem[iElem]->GetnNodes(); iNodes++)
16154  output_file << "\t" << elem[iElem]->GetNode(iNodes);
16155  output_file << "\t"<<iElem<< endl;
16156  }
16157 
16158  /*--- Write the node coordinates ---*/
16159 
16160  output_file << "NPOIN= " << nPoint << "\t" << nPointDomain << endl;
16161  output_file.precision(15);
16162  for (iPoint = 0; iPoint < nPoint; iPoint++) {
16163  for (iDim = 0; iDim < nDim; iDim++)
16164  output_file << scientific << "\t" << node[iPoint]->GetCoord(iDim) ;
16165 #ifndef HAVE_MPI
16166  output_file << "\t" << iPoint << endl;
16167 #else
16168  output_file << "\t" << iPoint << "\t" << node[iPoint]->GetGlobalIndex() << endl;
16169 #endif
16170 
16171  }
16172 
16173  /*--- Loop through and write the boundary info ---*/
16174 
16175  output_file << "NMARK= " << nMarker << endl;
16176  for (iMarker = 0; iMarker < nMarker; iMarker++) {
16177 
16178  /*--- Ignore SEND_RECEIVE for the moment ---*/
16179  if (bound[iMarker][0]->GetVTK_Type() != VERTEX) {
16180 
16181  Grid_Marker = config->GetMarker_All_TagBound(iMarker);
16182  output_file << "MARKER_TAG= " << Grid_Marker << endl;
16183  output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl;
16184 
16185  if (nDim == 2) {
16186  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
16187  output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
16188  for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++)
16189  output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ;
16190  output_file << iElem_Bound << endl;
16191  }
16192  }
16193 
16194  if (nDim == 3) {
16195  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
16196  output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
16197  for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes(); iNodes++)
16198  output_file << bound[iMarker][iElem_Bound]->GetNode(iNodes) << "\t" ;
16199  output_file << iElem_Bound << endl;
16200  }
16201  }
16202 
16203  } else if (bound[iMarker][0]->GetVTK_Type() == VERTEX) {
16204  output_file << "MARKER_TAG= SEND_RECEIVE" << endl;
16205  output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl;
16206  if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl;
16207  if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl;
16208 
16209  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
16210  output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" <<
16211  bound[iMarker][iElem_Bound]->GetNode(0) << "\t" <<
16212  bound[iMarker][iElem_Bound]->GetRotation_Type() << endl;
16213  }
16214 
16215  }
16216  }
16217 
16218  /*--- Get the total number of periodic transformations ---*/
16219 
16220  nPeriodic = config->GetnPeriodicIndex();
16221  output_file << "NPERIODIC= " << nPeriodic << endl;
16222 
16223  /*--- From iPeriodic obtain the iMarker ---*/
16224 
16225  for (iPeriodic = 0; iPeriodic < nPeriodic; iPeriodic++) {
16226 
16227  /*--- Retrieve the supplied periodic information. ---*/
16228 
16229  center = config->GetPeriodicCenter(iPeriodic);
16230  angles = config->GetPeriodicRotation(iPeriodic);
16231  transl = config->GetPeriodicTranslate(iPeriodic);
16232 
16233  output_file << "PERIODIC_INDEX= " << iPeriodic << endl;
16234  output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl;
16235  output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl;
16236  output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl;
16237 
16238  }
16239 
16240 
16241  output_file.close();
16242 }
16243 
16244 void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) {
16245  unsigned short iSmooth, nneigh, iMarker;
16246  su2double *Coord_Old, *Coord_Sum, *Coord, *Coord_i, *Coord_j, Position_Plane = 0.0;
16247  unsigned long iEdge, iPoint, jPoint, iVertex;
16248  su2double eps = 1E-6;
16249  bool NearField = false;
16250 
16251  Coord = new su2double [nDim];
16252 
16253  for (iPoint = 0; iPoint < GetnPoint(); iPoint++) {
16254  su2double *Coord = node[iPoint]->GetCoord();
16255  node[iPoint]->SetCoord_Old(Coord);
16256  }
16257 
16258  /*--- Jacobi iterations ---*/
16259  for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) {
16260 
16261  for (iPoint = 0; iPoint < nPoint; iPoint++)
16262  node[iPoint]->SetCoord_SumZero();
16263 
16264 
16265  /*--- Loop over Interior edges ---*/
16266  for (iEdge = 0; iEdge < nEdge; iEdge++) {
16267  iPoint = edge[iEdge]->GetNode(0);
16268  Coord_i = node[iPoint]->GetCoord();
16269 
16270  jPoint = edge[iEdge]->GetNode(1);
16271  Coord_j = node[jPoint]->GetCoord();
16272 
16273  /*--- Accumulate nearest neighbor Coord to Res_sum for each variable ---*/
16274  node[iPoint]->AddCoord_Sum(Coord_j);
16275  node[jPoint]->AddCoord_Sum(Coord_i);
16276 
16277  }
16278 
16279  /*--- Loop over all mesh points (Update Coords with averaged sum) ---*/
16280  for (iPoint = 0; iPoint < nPoint; iPoint++) {
16281  nneigh = node[iPoint]->GetnPoint();
16282  Coord_Sum = node[iPoint]->GetCoord_Sum();
16283  Coord_Old = node[iPoint]->GetCoord_Old();
16284 
16285  if (nDim == 2) {
16286  Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh));
16287  Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh));
16288  if ((NearField) && ((Coord_Old[1] > Position_Plane-eps) && (Coord_Old[1] < Position_Plane+eps)))
16289  Coord[1] = Coord_Old[1];
16290  }
16291 
16292  if (nDim == 3) {
16293  Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh));
16294  Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh));
16295  Coord[2] =(Coord_Old[2] + val_smooth_coeff*Coord_Sum[2]) /(1.0 + val_smooth_coeff*su2double(nneigh));
16296  if ((NearField) && ((Coord_Old[2] > Position_Plane-eps) && (Coord_Old[2] < Position_Plane+eps)))
16297  Coord[2] = Coord_Old[2];
16298  }
16299 
16300  node[iPoint]->SetCoord(Coord);
16301  }
16302 
16303  /*--- Copy boundary values ---*/
16304  for (iMarker = 0; iMarker < nMarker; iMarker++)
16305  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
16306  iPoint = vertex[iMarker][iVertex]->GetNode();
16307  Coord_Old = node[iPoint]->GetCoord_Old();
16308  node[iPoint]->SetCoord(Coord_Old);
16309  }
16310  }
16311 
16312  delete[] Coord;
16313 }
16314 
16315 bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem,
16316  unsigned short &face_second_elem) {
16317 
16318  /*--- Find repeated nodes between two elements to identify the common face ---*/
16319  unsigned long iPoint = 0, jPoint = 0;
16320  unsigned short face_node, iFace, iNode, jNode, nNodesFace;
16321  vector<unsigned long> CommonPoints, PointFaceFirst, PointFaceSecond;
16322  vector<unsigned long>::iterator IterPoint;
16323  pair<vector <unsigned long>::iterator, vector <unsigned long>::iterator> mypair;
16324  bool face_first_found = false, face_second_found =false;
16325 
16326  if (first_elem == second_elem) return false;
16327 
16328  for (iNode = 0; iNode < elem[first_elem]->GetnNodes(); iNode++) {
16329  iPoint = elem[first_elem]->GetNode(iNode);
16330  for (jNode = 0; jNode < elem[second_elem]->GetnNodes(); jNode++) {
16331  jPoint = elem[second_elem]->GetNode(jNode);
16332  if (iPoint == jPoint) {
16333  CommonPoints.push_back(iPoint);
16334  break;
16335  }
16336  }
16337  }
16338 
16339  /*--- Sort point in face and check that the list is unique ---*/
16340  sort( CommonPoints.begin(), CommonPoints.end());
16341  IterPoint = unique( CommonPoints.begin(), CommonPoints.end());
16342  CommonPoints.resize( distance(CommonPoints.begin(), IterPoint) );
16343 
16344  /*--- In 2D, the two elements must share two points that make up
16345  an edge, as all "faces" are edges in 2D. In 3D, we need to find
16346  exactly 3 (tri) or 4 (quad) common points. Return immediately to
16347  avoid a memory issue due to vectors of different lengths below. ---*/
16348 
16349  if ((nDim == 2) && (CommonPoints.size() != 2)) return false;
16350  if ((nDim == 3) && ((CommonPoints.size() != 3) &&
16351  (CommonPoints.size() != 4))) return false;
16352 
16353  /*--- Search the sequence in the first element ---*/
16354  for (iFace = 0; iFace < elem[first_elem]->GetnFaces(); iFace++) {
16355  nNodesFace = elem[first_elem]->GetnNodesFace(iFace);
16356 
16357  if (nNodesFace == CommonPoints.size()) {
16358  for (iNode = 0; iNode < nNodesFace; iNode++) {
16359  face_node = elem[first_elem]->GetFaces(iFace, iNode);
16360  PointFaceFirst.push_back(elem[first_elem]->GetNode(face_node));
16361  }
16362 
16363  /*--- Sort face_poin to perform comparison ---*/
16364  sort( PointFaceFirst.begin(), PointFaceFirst.end());
16365 
16366  /*--- List comparison ---*/
16367  mypair = mismatch (PointFaceFirst.begin(), PointFaceFirst.end(), CommonPoints.begin());
16368  if (mypair.first == PointFaceFirst.end()) {
16369  face_first_elem = iFace;
16370  face_first_found = true;
16371  break;
16372  }
16373 
16374  PointFaceFirst.erase (PointFaceFirst.begin(), PointFaceFirst.end());
16375  }
16376  }
16377 
16378  /*--- Search the secuence in the second element ---*/
16379  for (iFace = 0; iFace < elem[second_elem]->GetnFaces(); iFace++) {
16380  nNodesFace = elem[second_elem]->GetnNodesFace(iFace);
16381 
16382  if (nNodesFace == CommonPoints.size()) {
16383  for (iNode = 0; iNode < nNodesFace; iNode++) {
16384  face_node = elem[second_elem]->GetFaces(iFace, iNode);
16385  PointFaceSecond.push_back(elem[second_elem]->GetNode(face_node));
16386  }
16387 
16388  /*--- Sort face_poin to perform comparison ---*/
16389  sort( PointFaceSecond.begin(), PointFaceSecond.end());
16390 
16391  /*--- List comparison ---*/
16392  mypair = mismatch (PointFaceSecond.begin(), PointFaceSecond.end(), CommonPoints.begin());
16393  if (mypair.first == PointFaceSecond.end()) {
16394  face_second_elem = iFace;
16395  face_second_found = true;
16396  break;
16397  }
16398 
16399  PointFaceSecond.erase (PointFaceSecond.begin(), PointFaceSecond.end());
16400  }
16401  }
16402 
16403  if (face_first_found && face_second_found) return true;
16404  else return false;
16405 
16406 }
16407 
16408 void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) {
16409 
16410  unsigned long iElem, iPoint;
16411  unsigned short iDim;
16412  ofstream Tecplot_File;
16413 
16414  /*--- Open the tecplot file and write the header ---*/
16415 
16416  if (new_file) {
16417  Tecplot_File.open(mesh_filename, ios::out);
16418  Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl;
16419  if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl;
16420  if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl;
16421  }
16422  else Tecplot_File.open(mesh_filename, ios::out | ios::app);
16423 
16424  Tecplot_File << "ZONE T= ";
16425  if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, ";
16426  else Tecplot_File << "\"Deformed grid\", C=RED, ";
16427  Tecplot_File << "NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING= POINT";
16428  if (nDim == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl;
16429  if (nDim == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl;
16430 
16431  /*--- Adding coordinates ---*/
16432 
16433  for (iPoint = 0; iPoint < nPoint; iPoint++) {
16434  for (iDim = 0; iDim < nDim; iDim++)
16435  Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t";
16436  Tecplot_File << "\n";
16437  }
16438 
16439  /*--- Adding conectivity ---*/
16440 
16441  for (iElem = 0; iElem < nElem; iElem++) {
16442  if (elem[iElem]->GetVTK_Type() == TRIANGLE) {
16443  Tecplot_File <<
16444  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16445  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl;
16446  }
16447  if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) {
16448  Tecplot_File <<
16449  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16450  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl;
16451  }
16452  if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) {
16453  Tecplot_File <<
16454  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16455  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<<
16456  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
16457  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl;
16458  }
16459  if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) {
16460  Tecplot_File <<
16461  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16462  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
16463  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<<
16464  elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl;
16465  }
16466  if (elem[iElem]->GetVTK_Type() == PYRAMID) {
16467  Tecplot_File <<
16468  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16469  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
16470  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<<
16471  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl;
16472  }
16473  if (elem[iElem]->GetVTK_Type() == PRISM) {
16474  Tecplot_File <<
16475  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
16476  elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<<
16477  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<<
16478  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl;
16479  }
16480  }
16481 
16482  Tecplot_File.close();
16483 }
16484 
16485 void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) {
16486 
16487  ofstream Tecplot_File;
16488  unsigned long iPoint, Total_nElem_Bound, iElem, *PointSurface = NULL, nPointSurface = 0;
16489  unsigned short Coord_i, iMarker;
16490 
16491  /*--- It is important to do a renumbering to don't add points
16492  that do not belong to the surfaces ---*/
16493 
16494  PointSurface = new unsigned long[nPoint];
16495  for (iPoint = 0; iPoint < nPoint; iPoint++)
16496  if (node[iPoint]->GetBoundary()) {
16497  PointSurface[iPoint] = nPointSurface;
16498  nPointSurface++;
16499  }
16500 
16501  /*--- Compute the total number of elements ---*/
16502 
16503  Total_nElem_Bound = 0;
16504  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
16505  if (config->GetMarker_All_Plotting(iMarker) == YES) {
16506  Total_nElem_Bound += nElem_Bound[iMarker];
16507  }
16508  }
16509 
16510  /*--- Open the tecplot file and write the header ---*/
16511 
16512  if (new_file) {
16513  Tecplot_File.open(mesh_filename, ios::out);
16514  Tecplot_File << "TITLE= \"Visualization of the surface grid\"" << endl;
16515  if (nDim == 2) Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl;
16516  if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl;
16517  }
16518  else Tecplot_File.open(mesh_filename, ios::out | ios::app);
16519 
16520  if (Total_nElem_Bound != 0) {
16521 
16522  /*--- Write the header of the file ---*/
16523 
16524  Tecplot_File << "ZONE T= ";
16525  if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, ";
16526  else Tecplot_File << "\"Deformed grid\", C=RED, ";
16527  Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT";
16528  if (nDim == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl;
16529  if (nDim == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl;
16530 
16531  /*--- Only write the coordiantes of the points that are on the surfaces ---*/
16532 
16533  if (nDim == 3) {
16534  for (iPoint = 0; iPoint < nPoint; iPoint++)
16535  if (node[iPoint]->GetBoundary()) {
16536  for (Coord_i = 0; Coord_i < nDim-1; Coord_i++)
16537  Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " ";
16538  Tecplot_File << node[iPoint]->GetCoord(nDim-1) << "\n";
16539  }
16540  }
16541  else {
16542  for (iPoint = 0; iPoint < nPoint; iPoint++)
16543  if (node[iPoint]->GetBoundary()) {
16544  for (Coord_i = 0; Coord_i < nDim; Coord_i++)
16545  Tecplot_File << node[iPoint]->GetCoord(Coord_i) << " ";
16546  Tecplot_File << "\n";
16547  }
16548  }
16549 
16550  /*--- Write the cells using the new numbering ---*/
16551 
16552  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
16553  if (config->GetMarker_All_Plotting(iMarker) == YES)
16554  for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) {
16555  if (nDim == 2) {
16556  Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " "
16557  << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << endl;
16558  }
16559  if (nDim == 3) {
16560  if (bound[iMarker][iElem]->GetnNodes() == 3) {
16561  Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " "
16562  << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " "
16563  << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " "
16564  << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << endl;
16565  }
16566  if (bound[iMarker][iElem]->GetnNodes() == 4) {
16567  Tecplot_File << PointSurface[bound[iMarker][iElem]->GetNode(0)]+1 << " "
16568  << PointSurface[bound[iMarker][iElem]->GetNode(1)]+1 << " "
16569  << PointSurface[bound[iMarker][iElem]->GetNode(2)]+1 << " "
16570  << PointSurface[bound[iMarker][iElem]->GetNode(3)]+1 << endl;
16571  }
16572  }
16573  }
16574  }
16575  else {
16576 
16577  /*--- No elements in the surface ---*/
16578 
16579  if (nDim == 2) {
16580  Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl;
16581  Tecplot_File << "0.0 0.0"<< endl;
16582  Tecplot_File << "1 1"<< endl;
16583  }
16584  if (nDim == 3) {
16585  Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl;
16586  Tecplot_File << "0.0 0.0 0.0"<< endl;
16587  Tecplot_File << "1 1 1 1"<< endl;
16588  }
16589  }
16590 
16591  /*--- Dealocate memory and close the file ---*/
16592 
16593  delete[] PointSurface;
16594  Tecplot_File.close();
16595 
16596 }
16597 
16599 
16600 #ifdef HAVE_MPI
16601 #ifdef HAVE_METIS
16602 
16603  unsigned long iPoint, iElem, iElem_Triangle, iElem_Tetrahedron, nElem_Triangle,
16604  nElem_Tetrahedron;
16605  idx_t ne = 0, nn, *elmnts = NULL, *epart = NULL, *npart = NULL, nparts, edgecut, *eptr;
16606 
16607  if (size != SINGLE_ZONE)
16608  cout << endl <<"---------------------------- Grid partitioning --------------------------" << endl;
16609 
16610  unsigned short nDomain = size;
16611 
16612  nElem_Triangle = 0;
16613  nElem_Tetrahedron = 0;
16614  for (iElem = 0; iElem < GetnElem(); iElem++) {
16615  if (elem[iElem]->GetVTK_Type() == TRIANGLE) nElem_Triangle = nElem_Triangle + 1;
16616  if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) nElem_Triangle = nElem_Triangle + 2;
16617  if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 1;
16618  if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) nElem_Tetrahedron = nElem_Tetrahedron + 5;
16619  if (elem[iElem]->GetVTK_Type() == PYRAMID) nElem_Tetrahedron = nElem_Tetrahedron + 2;
16620  if (elem[iElem]->GetVTK_Type() == PRISM) nElem_Tetrahedron = nElem_Tetrahedron + 3;
16621  }
16622 
16623  if (GetnDim() == 2) {
16624  ne = nElem_Triangle;
16625  elmnts = new idx_t [ne*3];
16626  }
16627  if (GetnDim() == 3) {
16628  ne = nElem_Tetrahedron;
16629  elmnts = new idx_t [ne*4];
16630  }
16631 
16632  nn = nPoint;
16633  nparts = nDomain;
16634  epart = new idx_t [ne];
16635  npart = new idx_t [nn];
16636  eptr = new idx_t[ne+1];
16637 
16638  /*--- Initialize the color vector ---*/
16639 
16640  for (iPoint = 0; iPoint < nPoint; iPoint++)
16641  node[iPoint]->SetColor(0);
16642 
16643  if (nparts > 1) {
16644 
16645  iElem_Triangle = 0; iElem_Tetrahedron = 0;
16646  for (iElem = 0; iElem < GetnElem(); iElem++) {
16647  if (elem[iElem]->GetVTK_Type() == TRIANGLE) {
16648  elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0);
16649  elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1);
16650  elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2);
16651  eptr[iElem_Triangle] = 3*iElem_Triangle;
16652  iElem_Triangle++;
16653  }
16654  if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) {
16655  elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0);
16656  elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(1);
16657  elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(2);
16658  eptr[iElem_Triangle] = 3*iElem_Triangle;
16659  iElem_Triangle++;
16660  elmnts[3*iElem_Triangle+0]= elem[iElem]->GetNode(0);
16661  elmnts[3*iElem_Triangle+1]= elem[iElem]->GetNode(2);
16662  elmnts[3*iElem_Triangle+2]= elem[iElem]->GetNode(3);
16663  eptr[iElem_Triangle] = 3*iElem_Triangle;
16664  iElem_Triangle++;
16665  }
16666  if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) {
16667  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16668  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1);
16669  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2);
16670  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(3);
16671  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16672  iElem_Tetrahedron++;
16673  }
16674  if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) {
16675  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16676  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1);
16677  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2);
16678  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5);
16679  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16680  iElem_Tetrahedron++;
16681  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16682  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2);
16683  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3);
16684  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(7);
16685  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16686  iElem_Tetrahedron++;
16687  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16688  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(5);
16689  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7);
16690  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4);
16691  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16692  iElem_Tetrahedron++;
16693  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(2);
16694  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(7);
16695  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5);
16696  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(6);
16697  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16698  iElem_Tetrahedron++;
16699  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16700  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2);
16701  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(7);
16702  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(5);
16703  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16704  iElem_Tetrahedron++;
16705  }
16706  if (elem[iElem]->GetVTK_Type() == PYRAMID) {
16707  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16708  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1);
16709  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(2);
16710  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4);
16711  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16712  iElem_Tetrahedron++;
16713  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16714  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2);
16715  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3);
16716  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4);
16717  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16718  iElem_Tetrahedron++;
16719  }
16720  if (elem[iElem]->GetVTK_Type() == PRISM) {
16721  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16722  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(1);
16723  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(4);
16724  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2);
16725  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16726  iElem_Tetrahedron++;
16727  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(0);
16728  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(2);
16729  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(3);
16730  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(4);
16731  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16732  iElem_Tetrahedron++;
16733  elmnts[4*iElem_Tetrahedron+0]= elem[iElem]->GetNode(3);
16734  elmnts[4*iElem_Tetrahedron+1]= elem[iElem]->GetNode(4);
16735  elmnts[4*iElem_Tetrahedron+2]= elem[iElem]->GetNode(5);
16736  elmnts[4*iElem_Tetrahedron+3]= elem[iElem]->GetNode(2);
16737  eptr[iElem_Tetrahedron] = 4*iElem_Tetrahedron;
16738  iElem_Tetrahedron++;
16739  }
16740  }
16741 
16742  /*--- Add final value to element pointer array ---*/
16743 
16744  if (GetnDim() == 2) eptr[ne] = 3*ne;
16745  else eptr[ne] = 4*ne;
16746 
16747  METIS_PartMeshNodal(&ne, &nn, eptr, elmnts, NULL, NULL, &nparts, NULL, NULL, &edgecut, epart, npart);
16748 
16749  cout << "Finished partitioning using METIS. (" << edgecut << " edge cuts)." << endl;
16750 
16751  for (iPoint = 0; iPoint < nPoint; iPoint++)
16752  node[iPoint]->SetColor(npart[iPoint]);
16753  }
16754 
16755  delete[] epart;
16756  delete[] npart;
16757  delete[] elmnts;
16758  delete[] eptr;
16759 
16760 #endif
16761 
16762 #endif
16763 
16764 }
16765 
16767 
16768  /*--- Initialize the color vector ---*/
16769 
16770  for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++)
16771  node[iPoint]->SetColor(0);
16772 
16773  /*--- This routine should only ever be called if we have parallel support
16774  with MPI and have the ParMETIS library compiled and linked. ---*/
16775 
16776 #ifdef HAVE_MPI
16777 #ifdef HAVE_PARMETIS
16778 
16779  unsigned long iPoint;
16780  MPI_Comm comm = MPI_COMM_WORLD;
16781 
16782  /*--- Only call ParMETIS if we have more than one rank to avoid errors ---*/
16783 
16784  if (size > SINGLE_NODE) {
16785 
16786  /*--- Create some structures that ParMETIS needs for partitioning. ---*/
16787 
16788  idx_t numflag, nparts, edgecut, wgtflag, ncon;
16789 
16790  idx_t *vtxdist = new idx_t[size+1];
16791  idx_t *part = new idx_t[nPoint];
16792 
16793  real_t ubvec;
16794  real_t *tpwgts = new real_t[size];
16795 
16796  /*--- Some recommended defaults for the various ParMETIS options. ---*/
16797 
16798  wgtflag = 0;
16799  numflag = 0;
16800  ncon = 1;
16801  ubvec = 1.05;
16802  nparts = (idx_t)size;
16803  idx_t options[METIS_NOPTIONS];
16804  METIS_SetDefaultOptions(options);
16805  options[1] = 0;
16806 
16807  /*--- Fill the necessary ParMETIS data arrays. Note that xadj_size and
16808  adjacency_size are class data members that have been defined and set
16809  earlier in the partitioning process. ---*/
16810 
16811  for (int i = 0; i < size; i++) {
16812  tpwgts[i] = 1.0/((real_t)size);
16813  }
16814 
16815  vtxdist[0] = 0;
16816  for (int i = 0; i < size; i++) {
16817  vtxdist[i+1] = (idx_t)ending_node[i];
16818  }
16819 
16820  /*--- Calling ParMETIS ---*/
16821  if (rank == MASTER_NODE) cout << "Calling ParMETIS...";
16822  ParMETIS_V3_PartKway(vtxdist,xadj, adjacency, NULL, NULL, &wgtflag,
16823  &numflag, &ncon, &nparts, tpwgts, &ubvec, options,
16824  &edgecut, part, &comm);
16825  if (rank == MASTER_NODE) {
16826  cout << " graph partitioning complete (";
16827  cout << edgecut << " edge cuts)." << endl;
16828  }
16829 
16830  /*--- Store the results of the partitioning (note that this is local
16831  since each processor is calling ParMETIS in parallel and storing the
16832  results for its initial piece of the grid. ---*/
16833 
16834  for (iPoint = 0; iPoint < nPoint; iPoint++) {
16835  node[iPoint]->SetColor(part[iPoint]);
16836  }
16837 
16838  /*--- Free all memory needed for the ParMETIS structures ---*/
16839 
16840  delete [] vtxdist;
16841  delete [] part;
16842  delete [] tpwgts;
16843 
16844  }
16845 
16846  /*--- Delete the memory from the geometry class that carried the
16847  adjacency structure. ---*/
16848 
16849  delete [] xadj;
16850  delete [] adjacency;
16851 
16852 #endif
16853 #endif
16854 
16855 }
16856 
16858  unsigned long jPoint, Point_2, Point_3, iElem;
16859  su2double *Coord_j, *Coord_2, *Coord_3;
16860  unsigned short iDim;
16861 
16862  statistics[0] = 1e06;
16863  statistics[1] = 0;
16864 
16865  /*--- Loop interior edges ---*/
16866  for (iElem = 0; iElem < this->GetnElem(); iElem++) {
16867 
16868  if ((this->GetnDim() == 2) && (elem[iElem]->GetVTK_Type() == TRIANGLE)) {
16869 
16870  jPoint = elem[iElem]->GetNode(0); Coord_j = node[jPoint]->GetCoord();
16871  Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord();
16872  Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord();
16873 
16874  /*--- Compute sides of the triangle ---*/
16875  su2double a = 0, b = 0, c = 0;
16876  for (iDim = 0; iDim < nDim; iDim++) {
16877  a += (Coord_2[iDim]-Coord_j[iDim])*(Coord_2[iDim]-Coord_j[iDim]);
16878  b += (Coord_3[iDim]-Coord_j[iDim])*(Coord_3[iDim]-Coord_j[iDim]);
16879  c += (Coord_3[iDim]-Coord_2[iDim])*(Coord_3[iDim]-Coord_2[iDim]);
16880  }
16881  a = sqrt(a); b = sqrt(b); c = sqrt(c);
16882 
16883  /*--- Compute semiperimeter (s) and area ---*/
16884  su2double s = 0.5*(a + b + c);
16885  su2double Area = sqrt(s*(s-a)*(s-b)*(s-c));
16886 
16887  /*--- Compute radius of the circumcircle (R) and of the incircle (r) ---*/
16888  su2double R = (a*b*c) / (4.0*Area);
16889  su2double r = Area / s;
16890  su2double roR = r / R;
16891 
16892  /*--- Update statistics ---*/
16893  if (roR < statistics[0])
16894  statistics[0] = roR;
16895  statistics[1] += roR;
16896 
16897  }
16898  }
16899  statistics[1] /= this->GetnElem();
16900 
16901 }
16902 
16903 void CPhysicalGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print) {
16904 
16905  unsigned long iPoint;
16906  su2double RotVel[3], Distance[3], *Coord, Center[3], Omega[3], L_Ref;
16907 
16908  /*--- Center of rotation & angular velocity vector from config ---*/
16909 
16910  Center[0] = config->GetMotion_Origin_X(val_iZone);
16911  Center[1] = config->GetMotion_Origin_Y(val_iZone);
16912  Center[2] = config->GetMotion_Origin_Z(val_iZone);
16913  Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref();
16914  Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref();
16915  Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref();
16916  L_Ref = config->GetLength_Ref();
16917 
16918  /*--- Print some information to the console ---*/
16919 
16920  if (rank == MASTER_NODE && print) {
16921  cout << " Rotational origin (x, y, z): ( " << Center[0] << ", " << Center[1];
16922  cout << ", " << Center[2] << " )" << endl;
16923  cout << " Angular velocity about x, y, z axes: ( " << Omega[0] << ", ";
16924  cout << Omega[1] << ", " << Omega[2] << " ) rad/s" << endl;
16925  }
16926 
16927  /*--- Loop over all nodes and set the rotational velocity ---*/
16928 
16929  for (iPoint = 0; iPoint < nPoint; iPoint++) {
16930 
16931  /*--- Get the coordinates of the current node ---*/
16932 
16933  Coord = node[iPoint]->GetCoord();
16934 
16935  /*--- Calculate the non-dim. distance from the rotation center ---*/
16936 
16937  Distance[0] = (Coord[0]-Center[0])/L_Ref;
16938  Distance[1] = (Coord[1]-Center[1])/L_Ref;
16939  Distance[2] = 0.0;
16940  if (nDim == 3)
16941  Distance[2] = (Coord[2]-Center[2])/L_Ref;
16942 
16943  /*--- Calculate the angular velocity as omega X r ---*/
16944 
16945  RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]);
16946  RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]);
16947  RotVel[2] = 0.0;
16948  if (nDim == 3)
16949  RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]);
16950 
16951  /*--- Store the grid velocity at this node ---*/
16952 
16953  node[iPoint]->SetGridVel(RotVel);
16954 
16955  }
16956 
16957 }
16958 
16960 
16961  unsigned long iPoint, iVertex;
16962  unsigned short iMarker, iMarkerShroud;
16963  su2double RotVel[3];
16964 
16965  RotVel[0] = 0.0;
16966  RotVel[1] = 0.0;
16967  RotVel[2] = 0.0;
16968 
16969  /*--- Loop over all vertex in the shroud marker and set the rotational velocity to 0.0 ---*/
16970  for (iMarker = 0; iMarker < nMarker; iMarker++){
16971  for(iMarkerShroud=0; iMarkerShroud < config->GetnMarker_Shroud(); iMarkerShroud++){
16972  if(config->GetMarker_Shroud(iMarkerShroud) == config->GetMarker_All_TagBound(iMarker)){
16973  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
16974  iPoint = vertex[iMarker][iVertex]->GetNode();
16975  node[iPoint]->SetGridVel(RotVel);
16976  }
16977  }
16978  }
16979  }
16980 }
16981 
16982 void CPhysicalGeometry::SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print) {
16983 
16984  unsigned short iDim;
16985  unsigned long iPoint;
16986  su2double xDot[3] = {0.0,0.0,0.0};
16987 
16988  /*--- Get the translational velocity vector from config ---*/
16989 
16990  xDot[0] = config->GetTranslation_Rate_X(val_iZone)/config->GetVelocity_Ref();
16991  xDot[1] = config->GetTranslation_Rate_Y(val_iZone)/config->GetVelocity_Ref();
16992  xDot[2] = config->GetTranslation_Rate_Z(val_iZone)/config->GetVelocity_Ref();
16993 
16994  /*--- Print some information to the console ---*/
16995 
16996  if (rank == MASTER_NODE && print) {
16997  cout << " Non-dim. translational velocity: (" << xDot[0] << ", " << xDot[1];
16998  cout << ", " << xDot[2] << ")." << endl;
16999  }
17000 
17001  /*--- Loop over all nodes and set the translational velocity ---*/
17002 
17003  for (iPoint = 0; iPoint < nPoint; iPoint++) {
17004 
17005  /*--- Store the grid velocity at this node ---*/
17006 
17007  for (iDim = 0; iDim < nDim; iDim++) {
17008  node[iPoint]->SetGridVel(iDim,xDot[iDim]);
17009  }
17010 
17011  }
17012 
17013 }
17014 
17015 void CPhysicalGeometry::SetGridVelocity(CConfig *config, unsigned long iter) {
17016 
17017  /*--- Local variables ---*/
17018 
17019  su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL;
17020  su2double TimeStep, GridVel = 0.0;
17021  unsigned long iPoint;
17022  unsigned short iDim;
17023 
17024  /*--- Compute the velocity of each node in the volume mesh ---*/
17025 
17026  for (iPoint = 0; iPoint < GetnPoint(); iPoint++) {
17027 
17028  /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/
17029 
17030  Coord_nM1 = node[iPoint]->GetCoord_n1();
17031  Coord_n = node[iPoint]->GetCoord_n();
17032  Coord_nP1 = node[iPoint]->GetCoord();
17033 
17034  /*--- Unsteady time step ---*/
17035 
17036  TimeStep = config->GetDelta_UnstTimeND();
17037 
17038  /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/
17039 
17040  for (iDim = 0; iDim < nDim; iDim++) {
17041  if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST)
17042  GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep;
17043  if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)
17044  GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim]
17045  + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep);
17046 
17047  /*--- Store grid velocity for this point ---*/
17048 
17049  node[iPoint]->SetGridVel(iDim, GridVel);
17050  }
17051  }
17052 
17053 }
17054 
17056 
17057  unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR;
17058  unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector;
17059  su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_Coord = NULL, *Buffer_Send_Coord = NULL, *Coord = NULL, *newCoord = NULL;
17060  su2double *translation;
17061  newCoord = new su2double[nDim];
17062 
17063 #ifdef HAVE_MPI
17064  int send_to, receive_from;
17065  SU2_MPI::Status status;
17066 #endif
17067 
17068  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17069 
17070  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
17071  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
17072 
17073  MarkerS = iMarker; MarkerR = iMarker+1;
17074 
17075 #ifdef HAVE_MPI
17076  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
17077  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
17078 #endif
17079 
17080  nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR];
17081  nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim;
17082 
17083  /*--- Allocate Receive and send buffers ---*/
17084 
17085  Buffer_Receive_Coord = new su2double [nBufferR_Vector];
17086  Buffer_Send_Coord = new su2double[nBufferS_Vector];
17087 
17088  /*--- Copy the coordinates that should be sended ---*/
17089 
17090  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
17091  iPoint = vertex[MarkerS][iVertex]->GetNode();
17092  Coord = node[iPoint]->GetCoord();
17093  for (iDim = 0; iDim < nDim; iDim++)
17094  Buffer_Send_Coord[iDim*nVertexS+iVertex] = Coord[iDim];
17095  }
17096 
17097 #ifdef HAVE_MPI
17098  /*--- Send/Receive information using Sendrecv ---*/
17099  SU2_MPI::Sendrecv(Buffer_Send_Coord, nBufferS_Vector, MPI_DOUBLE, send_to,0,
17100  Buffer_Receive_Coord, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status);
17101 #else
17102 
17103  /*--- Receive information without MPI ---*/
17104  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17105  for (iDim = 0; iDim < nDim; iDim++)
17106  Buffer_Receive_Coord[iDim*nVertexR+iVertex] = Buffer_Send_Coord[iDim*nVertexR+iVertex];
17107  }
17108 
17109 #endif
17110 
17111  /*--- Deallocate send buffer ---*/
17112 
17113  delete [] Buffer_Send_Coord;
17114 
17115  /*--- Do the coordinate transformation ---*/
17116 
17117  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17118 
17119  /*--- Find point and its type of transformation ---*/
17120 
17121  iPoint = vertex[MarkerR][iVertex]->GetNode();
17122  iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type();
17123 
17124  /*--- Retrieve the supplied periodic information. ---*/
17125 
17126  angles = config->GetPeriodicRotation(iPeriodic_Index);
17127  translation = config->GetPeriodicTranslate(iPeriodic_Index);
17128 
17129  /*--- Store angles separately for clarity. ---*/
17130 
17131  theta = angles[0]; phi = angles[1]; psi = angles[2];
17132  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
17133  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
17134 
17135  /*--- Compute the rotation matrix. Note that the implicit
17136  ordering is rotation about the x-axis, y-axis,
17137  then z-axis. Note that this is the transpose of the matrix
17138  used during the preprocessing stage. ---*/
17139 
17140  rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
17141  rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
17142  rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi;
17143 
17144  /*--- Copy coordinates before performing transformation. ---*/
17145 
17146  for (iDim = 0; iDim < nDim; iDim++)
17147  newCoord[iDim] = Buffer_Receive_Coord[iDim*nVertexR+iVertex];
17148 
17149  /*--- Rotate the coordinates. ---*/
17150 
17151  if (nDim == 2) {
17152  newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] +
17153  rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]) - translation[0];
17154  newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] +
17155  rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex]) - translation[1];
17156  }
17157  else {
17158  newCoord[0] = (rotMatrix[0][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] +
17159  rotMatrix[0][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] +
17160  rotMatrix[0][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]);
17161  newCoord[1] = (rotMatrix[1][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] +
17162  rotMatrix[1][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] +
17163  rotMatrix[1][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]);
17164  newCoord[2] = (rotMatrix[2][0]*Buffer_Receive_Coord[0*nVertexR+iVertex] +
17165  rotMatrix[2][1]*Buffer_Receive_Coord[1*nVertexR+iVertex] +
17166  rotMatrix[2][2]*Buffer_Receive_Coord[2*nVertexR+iVertex]);
17167  }
17168 
17169  /*--- Copy transformed coordinates back into buffer. ---*/
17170 
17171  for (iDim = 0; iDim < nDim; iDim++)
17172  node[iPoint]->SetCoord(iDim, newCoord[iDim]);
17173 
17174  }
17175 
17176  /*--- Deallocate receive buffer. ---*/
17177 
17178  delete [] Buffer_Receive_Coord;
17179 
17180  }
17181 
17182  }
17183 
17184  delete [] newCoord;
17185 
17186 }
17187 
17189 
17190  unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR;
17191  unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector;
17192  su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi, *Buffer_Receive_GridVel = NULL, *Buffer_Send_GridVel = NULL, *GridVel = NULL, *newGridVel = NULL;
17193 
17194  newGridVel = new su2double[nDim];
17195 
17196 #ifdef HAVE_MPI
17197  int send_to, receive_from;
17198  SU2_MPI::Status status;
17199 #endif
17200 
17201  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17202 
17203  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
17204  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
17205 
17206  MarkerS = iMarker; MarkerR = iMarker+1;
17207 
17208 #ifdef HAVE_MPI
17209  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
17210  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
17211 #endif
17212 
17213  nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR];
17214  nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim;
17215 
17216  /*--- Allocate Receive and send buffers ---*/
17217 
17218  Buffer_Receive_GridVel = new su2double [nBufferR_Vector];
17219  Buffer_Send_GridVel = new su2double[nBufferS_Vector];
17220 
17221  /*--- Copy the grid velocity that should be sended ---*/
17222 
17223  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
17224  iPoint = vertex[MarkerS][iVertex]->GetNode();
17225  GridVel = node[iPoint]->GetGridVel();
17226  for (iDim = 0; iDim < nDim; iDim++)
17227  Buffer_Send_GridVel[iDim*nVertexS+iVertex] = GridVel[iDim];
17228  }
17229 
17230 #ifdef HAVE_MPI
17231  /*--- Send/Receive information using Sendrecv ---*/
17232  SU2_MPI::Sendrecv(Buffer_Send_GridVel, nBufferS_Vector, MPI_DOUBLE, send_to,0,
17233  Buffer_Receive_GridVel, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status);
17234 #else
17235 
17236  /*--- Receive information without MPI ---*/
17237  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17238  for (iDim = 0; iDim < nDim; iDim++)
17239  Buffer_Receive_GridVel[iDim*nVertexR+iVertex] = Buffer_Send_GridVel[iDim*nVertexR+iVertex];
17240  }
17241 
17242 #endif
17243 
17244  /*--- Deallocate send buffer ---*/
17245 
17246  delete [] Buffer_Send_GridVel;
17247 
17248  /*--- Do the coordinate transformation ---*/
17249 
17250  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17251 
17252  /*--- Find point and its type of transformation ---*/
17253 
17254  iPoint = vertex[MarkerR][iVertex]->GetNode();
17255  iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type();
17256 
17257  /*--- Retrieve the supplied periodic information. ---*/
17258 
17259  angles = config->GetPeriodicRotation(iPeriodic_Index);
17260 
17261  /*--- Store angles separately for clarity. ---*/
17262  theta = angles[0]; phi = angles[1]; psi = angles[2];
17263  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
17264  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
17265 
17266  /*--- Compute the rotation matrix. Note that the implicit
17267  ordering is rotation about the x-axis, y-axis,
17268  then z-axis. Note that this is the transpose of the matrix
17269  used during the preprocessing stage. ---*/
17270 
17271  rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
17272  rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
17273  rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi;
17274 
17275  /*--- Copy grid velocity before performing transformation. ---*/
17276 
17277  for (iDim = 0; iDim < nDim; iDim++)
17278  newGridVel[iDim] = Buffer_Receive_GridVel[iDim*nVertexR+iVertex];
17279 
17280  if (nDim == 2) {
17281  newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] +
17282  rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]);
17283  newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] +
17284  rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex]);
17285  }
17286  else {
17287  newGridVel[0] = (rotMatrix[0][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] +
17288  rotMatrix[0][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] +
17289  rotMatrix[0][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]);
17290  newGridVel[1] = (rotMatrix[1][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] +
17291  rotMatrix[1][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] +
17292  rotMatrix[1][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]);
17293  newGridVel[2] = (rotMatrix[2][0]*Buffer_Receive_GridVel[0*nVertexR+iVertex] +
17294  rotMatrix[2][1]*Buffer_Receive_GridVel[1*nVertexR+iVertex] +
17295  rotMatrix[2][2]*Buffer_Receive_GridVel[2*nVertexR+iVertex]);
17296  }
17297 
17298  /*--- Copy transformed grid velocity back into buffer. ---*/
17299 
17300  for (iDim = 0; iDim < nDim; iDim++)
17301  node[iPoint]->SetGridVel(iDim, newGridVel[iDim]);
17302 
17303  }
17304 
17305  /*--- Deallocate receive buffer ---*/
17306 
17307  delete [] Buffer_Receive_GridVel;
17308 
17309  }
17310 
17311  }
17312 
17313  delete [] newGridVel;
17314 
17315 }
17316 
17318 
17319  unsigned short iDim, iMarker, iPeriodic_Index, MarkerS, MarkerR;
17320  unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector;
17321  su2double rotMatrix[3][3], *angles, theta, cosTheta, sinTheta, phi, cosPhi, sinPhi, psi, cosPsi, sinPsi;
17322 
17323  su2double *Buffer_Receive_Coord_n = NULL, *Buffer_Send_Coord_n = NULL, *Coord_n = NULL, *newCoord_n = NULL;
17324 
17325  newCoord_n = new su2double[nDim];
17326 
17327 #ifdef HAVE_MPI
17328  int send_to, receive_from;
17329  SU2_MPI::Status status;
17330 #endif
17331 
17332  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17333 
17334  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
17335  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
17336 
17337  MarkerS = iMarker; MarkerR = iMarker+1;
17338 
17339 #ifdef HAVE_MPI
17340  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
17341  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
17342 #endif
17343 
17344  nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR];
17345  nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim;
17346 
17347  /*--- Allocate Receive and send buffers ---*/
17348 
17349  Buffer_Receive_Coord_n = new su2double [nBufferR_Vector];
17350  Buffer_Send_Coord_n = new su2double[nBufferS_Vector];
17351 
17352  /*--- Copy the coordinates that should be sended ---*/
17353 
17354  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
17355  iPoint = vertex[MarkerS][iVertex]->GetNode();
17356  Coord_n = node[iPoint]->GetCoord_n();
17357  for (iDim = 0; iDim < nDim; iDim++)
17358  Buffer_Send_Coord_n[iDim*nVertexS+iVertex] = Coord_n[iDim];
17359  }
17360 
17361 #ifdef HAVE_MPI
17362  /*--- Send/Receive information using Sendrecv ---*/
17363  SU2_MPI::Sendrecv(Buffer_Send_Coord_n, nBufferS_Vector, MPI_DOUBLE, send_to,0,
17364  Buffer_Receive_Coord_n, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status);
17365 #else
17366 
17367  /*--- Receive information without MPI ---*/
17368  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17369  for (iDim = 0; iDim < nDim; iDim++)
17370  Buffer_Receive_Coord_n[iDim*nVertexR+iVertex] = Buffer_Send_Coord_n[iDim*nVertexR+iVertex];
17371  }
17372 
17373 #endif
17374 
17375  /*--- Deallocate send buffer ---*/
17376 
17377  delete [] Buffer_Send_Coord_n;
17378 
17379  /*--- Do the coordinate transformation ---*/
17380 
17381  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17382 
17383  /*--- Find point and its type of transformation ---*/
17384 
17385  iPoint = vertex[MarkerR][iVertex]->GetNode();
17386  iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type();
17387 
17388  /*--- Retrieve the supplied periodic information. ---*/
17389 
17390  angles = config->GetPeriodicRotation(iPeriodic_Index);
17391 
17392  /*--- Store angles separately for clarity. ---*/
17393 
17394  theta = angles[0]; phi = angles[1]; psi = angles[2];
17395  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
17396  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
17397 
17398  /*--- Compute the rotation matrix. Note that the implicit
17399  ordering is rotation about the x-axis, y-axis,
17400  then z-axis. Note that this is the transpose of the matrix
17401  used during the preprocessing stage. ---*/
17402 
17403  rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
17404  rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
17405  rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi;
17406 
17407  /*--- Copy coordinates before performing transformation. ---*/
17408 
17409  for (iDim = 0; iDim < nDim; iDim++)
17410  newCoord_n[iDim] = Buffer_Receive_Coord_n[iDim*nVertexR+iVertex];
17411 
17412  /*--- Rotate the coordinates. ---*/
17413 
17414  if (nDim == 2) {
17415  newCoord_n[0] = (rotMatrix[0][0]*Buffer_Receive_Coord_n[0*nVertexR+iVertex] +
17416  rotMatrix[0][1]*Buffer_Receive_Coord_n[1*nVertexR+iVertex]);
17417  newCoord_n[1] = (rotMatrix[1][0]*Buffer_Receive_Coord_n[0*nVertexR+iVertex] +
17418  rotMatrix[1][1]*Buffer_Receive_Coord_n[1*nVertexR+iVertex]);
17419  }
17420  else {
17421  newCoord_n[0] = (rotMatrix[0][0]*Buffer_Receive_Coord_n[0*nVertexR+iVertex] +
17422  rotMatrix[0][1]*Buffer_Receive_Coord_n[1*nVertexR+iVertex] +
17423  rotMatrix[0][2]*Buffer_Receive_Coord_n[2*nVertexR+iVertex]);
17424  newCoord_n[1] = (rotMatrix[1][0]*Buffer_Receive_Coord_n[0*nVertexR+iVertex] +
17425  rotMatrix[1][1]*Buffer_Receive_Coord_n[1*nVertexR+iVertex] +
17426  rotMatrix[1][2]*Buffer_Receive_Coord_n[2*nVertexR+iVertex]);
17427  newCoord_n[2] = (rotMatrix[2][0]*Buffer_Receive_Coord_n[0*nVertexR+iVertex] +
17428  rotMatrix[2][1]*Buffer_Receive_Coord_n[1*nVertexR+iVertex] +
17429  rotMatrix[2][2]*Buffer_Receive_Coord_n[2*nVertexR+iVertex]);
17430  }
17431 
17432  /*--- Copy transformed coordinates back into buffer. ---*/
17433 
17434  node[iPoint]->SetCoord_n(newCoord_n);
17435 
17436  }
17437 
17438  /*--- Deallocate receive buffer. ---*/
17439 
17440  delete [] Buffer_Receive_Coord_n;
17441 
17442  }
17443 
17444  }
17445 
17446  delete [] newCoord_n;
17447 
17448  /*--------------------------------------------------------------------------------------------------*/
17449  /*--- We repeat the process for the coordinate n-1, in the case that the simulation is 2nd order ---*/
17450  /*--------------------------------------------------------------------------------------------------*/
17451 
17452  if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND) {
17453 
17454  su2double *Buffer_Receive_Coord_n1 = NULL, *Buffer_Send_Coord_n1 = NULL, *Coord_n1 = NULL, *newCoord_n1 = NULL;
17455  newCoord_n1 = new su2double[nDim];
17456 
17457  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17458 
17459  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
17460  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
17461 
17462  MarkerS = iMarker; MarkerR = iMarker+1;
17463 
17464 #ifdef HAVE_MPI
17465  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
17466  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
17467 #endif
17468 
17469  nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR];
17470  nBufferS_Vector = nVertexS*nDim; nBufferR_Vector = nVertexR*nDim;
17471 
17472  /*--- Allocate Receive and send buffers ---*/
17473 
17474  Buffer_Receive_Coord_n1 = new su2double [nBufferR_Vector];
17475  Buffer_Send_Coord_n1 = new su2double[nBufferS_Vector];
17476 
17477  /*--- Copy the coordinates that should be sended ---*/
17478 
17479  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
17480  iPoint = vertex[MarkerS][iVertex]->GetNode();
17481  Coord_n1 = node[iPoint]->GetCoord_n1();
17482  for (iDim = 0; iDim < nDim; iDim++)
17483  Buffer_Send_Coord_n1[iDim*nVertexS+iVertex] = Coord_n1[iDim];
17484  }
17485 
17486 #ifdef HAVE_MPI
17487  /*--- Send/Receive information using Sendrecv ---*/
17488  SU2_MPI::Sendrecv(Buffer_Send_Coord_n1, nBufferS_Vector, MPI_DOUBLE, send_to,0,
17489  Buffer_Receive_Coord_n1, nBufferR_Vector, MPI_DOUBLE, receive_from,0, MPI_COMM_WORLD, &status);
17490 #else
17491 
17492  /*--- Receive information without MPI ---*/
17493  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17494  for (iDim = 0; iDim < nDim; iDim++)
17495  Buffer_Receive_Coord_n1[iDim*nVertexR+iVertex] = Buffer_Send_Coord_n1[iDim*nVertexR+iVertex];
17496  }
17497 
17498 #endif
17499 
17500  /*--- Deallocate send buffer ---*/
17501 
17502  delete [] Buffer_Send_Coord_n1;
17503 
17504  /*--- Do the coordinate transformation ---*/
17505 
17506  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17507 
17508  /*--- Find point and its type of transformation ---*/
17509 
17510  iPoint = vertex[MarkerR][iVertex]->GetNode();
17511  iPeriodic_Index = vertex[MarkerR][iVertex]->GetRotation_Type();
17512 
17513  /*--- Retrieve the supplied periodic information. ---*/
17514 
17515  angles = config->GetPeriodicRotation(iPeriodic_Index);
17516 
17517  /*--- Store angles separately for clarity. ---*/
17518 
17519  theta = angles[0]; phi = angles[1]; psi = angles[2];
17520  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
17521  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
17522 
17523  /*--- Compute the rotation matrix. Note that the implicit
17524  ordering is rotation about the x-axis, y-axis,
17525  then z-axis. Note that this is the transpose of the matrix
17526  used during the preprocessing stage. ---*/
17527 
17528  rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[2][0] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
17529  rotMatrix[0][1] = cosPhi*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
17530  rotMatrix[0][2] = -sinPhi; rotMatrix[1][2] = sinTheta*cosPhi; rotMatrix[2][2] = cosTheta*cosPhi;
17531 
17532  /*--- Copy coordinates before performing transformation. ---*/
17533 
17534  for (iDim = 0; iDim < nDim; iDim++)
17535  newCoord_n1[iDim] = Buffer_Receive_Coord_n1[iDim*nVertexR+iVertex];
17536 
17537  /*--- Rotate the coordinates. ---*/
17538 
17539  if (nDim == 2) {
17540  newCoord_n1[0] = (rotMatrix[0][0]*Buffer_Receive_Coord_n1[0*nVertexR+iVertex] +
17541  rotMatrix[0][1]*Buffer_Receive_Coord_n1[1*nVertexR+iVertex]);
17542  newCoord_n1[1] = (rotMatrix[1][0]*Buffer_Receive_Coord_n1[0*nVertexR+iVertex] +
17543  rotMatrix[1][1]*Buffer_Receive_Coord_n1[1*nVertexR+iVertex]);
17544  }
17545  else {
17546  newCoord_n1[0] = (rotMatrix[0][0]*Buffer_Receive_Coord_n1[0*nVertexR+iVertex] +
17547  rotMatrix[0][1]*Buffer_Receive_Coord_n1[1*nVertexR+iVertex] +
17548  rotMatrix[0][2]*Buffer_Receive_Coord_n1[2*nVertexR+iVertex]);
17549  newCoord_n1[1] = (rotMatrix[1][0]*Buffer_Receive_Coord_n1[0*nVertexR+iVertex] +
17550  rotMatrix[1][1]*Buffer_Receive_Coord_n1[1*nVertexR+iVertex] +
17551  rotMatrix[1][2]*Buffer_Receive_Coord_n1[2*nVertexR+iVertex]);
17552  newCoord_n1[2] = (rotMatrix[2][0]*Buffer_Receive_Coord_n1[0*nVertexR+iVertex] +
17553  rotMatrix[2][1]*Buffer_Receive_Coord_n1[1*nVertexR+iVertex] +
17554  rotMatrix[2][2]*Buffer_Receive_Coord_n1[2*nVertexR+iVertex]);
17555  }
17556 
17557  /*--- Copy transformed coordinates back into buffer. ---*/
17558 
17559  node[iPoint]->SetCoord_n1(newCoord_n1);
17560 
17561  }
17562 
17563  /*--- Deallocate receive buffer. ---*/
17564 
17565  delete [] Buffer_Receive_Coord_n1;
17566 
17567  }
17568 
17569  }
17570 
17571  delete [] newCoord_n1;
17572 
17573  }
17574 
17575  /*--------------------------------------------------------------------------------------------------*/
17576 
17577 }
17578 
17580 
17581  unsigned short iMarker, MarkerS, MarkerR;
17582  unsigned long iVertex, iPoint, nVertexS, nVertexR, nBufferS, nBufferR;
17583  su2double *Buffer_Receive = NULL, *Buffer_Send = NULL;
17584 
17585 #ifdef HAVE_MPI
17586  int send_to, receive_from;
17587  SU2_MPI::Status status;
17588 #endif
17589 
17590  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17591 
17592  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
17593  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
17594 
17595  MarkerS = iMarker; MarkerR = iMarker+1;
17596 
17597 #ifdef HAVE_MPI
17598  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
17599  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
17600 #endif
17601 
17602  nVertexS = nVertex[MarkerS]; nVertexR = nVertex[MarkerR];
17603  nBufferS = nVertexS; nBufferR = nVertexR;
17604 
17605  /*--- Allocate Receive and send buffers ---*/
17606 
17607  Buffer_Receive = new su2double [nBufferR];
17608  Buffer_Send = new su2double[nBufferS];
17609 
17610  /*--- Copy the grid velocity that should be sent ---*/
17611 
17612  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
17613  iPoint = vertex[MarkerS][iVertex]->GetNode();
17614  const su2double max_length = node[iPoint]->GetMaxLength();
17615  Buffer_Send[iVertex] = max_length;
17616  }
17617 
17618 #ifdef HAVE_MPI
17619  /*--- Send/Receive information using Sendrecv ---*/
17620  SU2_MPI::Sendrecv(Buffer_Send, nBufferS, MPI_DOUBLE, send_to, 0,
17621  Buffer_Receive, nBufferR, MPI_DOUBLE, receive_from, 0,
17622  MPI_COMM_WORLD, &status);
17623 #else
17624 
17625  /*--- Receive information without MPI ---*/
17626  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17627  Buffer_Receive[iVertex] = Buffer_Send[iVertex];
17628  }
17629 
17630 #endif
17631 
17632  /*--- Deallocate send buffer ---*/
17633 
17634  delete [] Buffer_Send;
17635 
17636 
17637  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
17638  iPoint = vertex[MarkerR][iVertex]->GetNode();
17639  node[iPoint]->SetMaxLength(Buffer_Receive[iVertex]);
17640  }
17641 
17642  /*--- Deallocate receive buffer ---*/
17643 
17644  delete [] Buffer_Receive;
17645 
17646  }
17647 
17648  }
17649 
17650 }
17651 
17653 
17654  unsigned short iMarker, jMarker, kMarker = 0, iPeriodic, iDim, nPeriodic = 0, VTK_Type;
17655  unsigned long iNode, iIndex, iVertex, iPoint, iElem, kElem;
17656  unsigned long jElem, kPoint = 0, jVertex = 0, jPoint = 0, pPoint = 0, nPointPeriodic, newNodes[4] = {0,0,0,0};
17657  vector<unsigned long>::iterator IterElem, IterPoint[MAX_NUMBER_PERIODIC][2];
17658  su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}},
17659  translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi,
17660  dx, dy, dz, rotCoord[3], epsilon = 1e-10, mindist = 1e6, *Coord_i, *Coord_j, dist = 0.0;
17661  bool isBadMatch = false;
17662 
17663  /*--- Check this dimensionalization ---*/
17664 
17665  vector<unsigned long> OldBoundaryElems[100];
17666  vector<unsigned long>::iterator IterNewElem[100];
17667 
17668  /*--- We only create the mirror structure for the second boundary ---*/
17669  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17670  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) {
17671  /*--- Evaluate the number of periodic boundary conditions ---*/
17672  nPeriodic++;
17673  }
17674  }
17675  bool *CreateMirror = new bool[nPeriodic+1];
17676  CreateMirror[0] = false;
17677  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17678  if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false;
17679  else CreateMirror[iPeriodic] = true;
17680  }
17681 
17682  /*--- Send an initial message to the console. ---*/
17683  cout << "Setting the periodic boundary conditions." << endl;
17684 
17685  /*--- Loop through each marker to find any periodic boundaries. ---*/
17686  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
17687  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) {
17688 
17689  /*--- Get marker index of the periodic donor boundary. ---*/
17690  jMarker = config->GetMarker_Periodic_Donor(config->GetMarker_All_TagBound(iMarker));
17691 
17692  /*--- Write some info to the console. ---*/
17693  cout << "Checking " << config->GetMarker_All_TagBound(iMarker);
17694  cout << " boundary against periodic donor, " << config->GetMarker_All_TagBound(jMarker) << ". ";
17695 
17696  /*--- Retrieve the supplied periodic information. ---*/
17697  center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker));
17698  angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker));
17699  trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker));
17700 
17701  /*--- Store (center+trans) as it is constant and will be added on. ---*/
17702  translation[0] = center[0] + trans[0];
17703  translation[1] = center[1] + trans[1];
17704  translation[2] = center[2] + trans[2];
17705 
17706  /*--- Store angles separately for clarity. Compute sines/cosines. ---*/
17707  theta = angles[0];
17708  phi = angles[1];
17709  psi = angles[2];
17710 
17711  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
17712  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
17713 
17714  /*--- Compute the rotation matrix. Note that the implicit
17715  ordering is rotation about the x-axis, y-axis, then z-axis. ---*/
17716  rotMatrix[0][0] = cosPhi*cosPsi;
17717  rotMatrix[1][0] = cosPhi*sinPsi;
17718  rotMatrix[2][0] = -sinPhi;
17719 
17720  rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi;
17721  rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi;
17722  rotMatrix[2][1] = sinTheta*cosPhi;
17723 
17724  rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
17725  rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
17726  rotMatrix[2][2] = cosTheta*cosPhi;
17727 
17728  /*--- Loop through all vertices and find/set the periodic point. ---*/
17729  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
17730 
17731  /*--- Retrieve node information for this boundary point. ---*/
17732  iPoint = vertex[iMarker][iVertex]->GetNode();
17733  Coord_i = node[iPoint]->GetCoord();
17734 
17735  /*--- Get the position vector from rot center to point. ---*/
17736  dx = Coord_i[0] - center[0];
17737  dy = Coord_i[1] - center[1];
17738  if (nDim == 3) {
17739  dz = Coord_i[2] - center[2];
17740  } else {
17741  dz = 0.0;
17742  }
17743 
17744  /*--- Compute transformed point coordinates. ---*/
17745  rotCoord[0] = rotMatrix[0][0]*dx
17746  + rotMatrix[0][1]*dy
17747  + rotMatrix[0][2]*dz + translation[0];
17748 
17749  rotCoord[1] = rotMatrix[1][0]*dx
17750  + rotMatrix[1][1]*dy
17751  + rotMatrix[1][2]*dz + translation[1];
17752 
17753  rotCoord[2] = rotMatrix[2][0]*dx
17754  + rotMatrix[2][1]*dy
17755  + rotMatrix[2][2]*dz + translation[2];
17756 
17757  /*--- Perform a search to find the closest donor point. ---*/
17758  mindist = 1e10;
17759  for (jVertex = 0; jVertex < nVertex[jMarker]; jVertex++) {
17760 
17761  /*--- Retrieve information for this jPoint. ---*/
17762  jPoint = vertex[jMarker][jVertex]->GetNode();
17763  Coord_j = node[jPoint]->GetCoord();
17764 
17765  /*--- Check the distance between the computed periodic
17766  location and this jPoint. ---*/
17767  dist = 0.0;
17768  for (iDim = 0; iDim < nDim; iDim++) {
17769  dist += (Coord_j[iDim]-rotCoord[iDim])*(Coord_j[iDim]-rotCoord[iDim]);
17770  }
17771  dist = sqrt(dist);
17772 
17773  /*--- Store vertex information if this is the closest
17774  point found thus far. ---*/
17775  if (dist < mindist) { mindist = dist; pPoint = jPoint; }
17776  }
17777 
17778  /*--- Set the periodic point for this iPoint. ---*/
17779  vertex[iMarker][iVertex]->SetDonorPoint(pPoint, MASTER_NODE);
17780 
17781  /*--- Print warning if the nearest point was not within
17782  the specified tolerance. Computation will continue. ---*/
17783  if (mindist > epsilon) {
17784  isBadMatch = true;
17785  cout.precision(10);
17786  cout << endl;
17787  cout << " Bad match for point " << iPoint << ".\tNearest";
17788  cout << " donor distance: " << scientific << mindist << ".";
17789  }
17790  }
17791 
17792  /*--- Print final warning when finding bad matches. ---*/
17793  if (isBadMatch) {
17794  cout << endl;
17795  cout << "\n !!! Warning !!!" << endl;
17796  cout << "Bad matches found. Computation will continue, but be cautious.\n";
17797  }
17798  cout << endl;
17799  isBadMatch = false;
17800 
17801  }
17802 
17803  /*--- Create a vector to identify the points that belong to each periodic boundary condition ---*/
17804  bool *PeriodicBC = new bool [nPoint];
17805  for (iPoint = 0; iPoint < nPoint; iPoint++) PeriodicBC[iPoint] = false;
17806 
17807  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
17808  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY)
17809  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
17810  iPoint = vertex[iMarker][iVertex]->GetNode();
17811  PeriodicBC[iPoint] = true;
17812  }
17813 
17814  /*--- Determine the new points that must be added to each periodic boundary,
17815  note that only one of the boundaries require the extra data ---*/
17816  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17817  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) {
17818  iPeriodic = config->GetMarker_All_PerBound(iMarker);
17819 
17820  /*--- An integer identify the periodic boundary condition --*/
17821  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
17822 
17823  /*--- iPoint is the original point on the surface and jPoint is the
17824  equivalent point in the other periodic surface ---*/
17825  iPoint = vertex[iMarker][iVertex]->GetNode();
17826  jPoint = vertex[iMarker][iVertex]->GetDonorPoint();
17827 
17828  /*--- First the case in which it is necessary to create a mirror set of elements ---*/
17829  if (CreateMirror[iPeriodic]) {
17830  /*--- Now we must determine the neighbor points (including indirect ones) to the periodic points
17831  and store all the information (in this list we do not include the points
17832  that already belong to the periodic boundary), we also add the elements that
17833  share a point with the periodic boundary condition ---*/
17834  for (iIndex = 0; iIndex < node[jPoint]->GetnElem(); iIndex++) {
17835  iElem = node[jPoint]->GetElem(iIndex);
17836  PeriodicElem[iPeriodic].push_back(iElem);
17837  for (unsigned short iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode ++) {
17838  kPoint = elem[iElem]->GetNode(iNode);
17839  if (!PeriodicBC[kPoint]) PeriodicPoint[iPeriodic][0].push_back(kPoint);
17840  }
17841  }
17842  }
17843  /*--- Second the case where no new element is added, neither points ---*/
17844  else {
17845  PeriodicPoint[iPeriodic][0].push_back(jPoint);
17846  PeriodicPoint[iPeriodic][1].push_back(iPoint);
17847  }
17848  }
17849  }
17850  }
17851 
17852  /*--- Sort the points that must be sended and delete repeated points ---*/
17853  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17854  if (CreateMirror[iPeriodic]) {
17855  sort( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end());
17856  IterPoint[iPeriodic][0] = unique( PeriodicPoint[iPeriodic][0].begin(), PeriodicPoint[iPeriodic][0].end());
17857  PeriodicPoint[iPeriodic][0].resize( IterPoint[iPeriodic][0] - PeriodicPoint[iPeriodic][0].begin() );
17858  }
17859  }
17860 
17861  /*--- Create a list of the points that receive the values (only the new points) ---*/
17862  nPointPeriodic = nPoint;
17863  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17864  if (CreateMirror[iPeriodic]) {
17865  for (iPoint = 0; iPoint < PeriodicPoint[iPeriodic][0].size(); iPoint++) {
17866  PeriodicPoint[iPeriodic][1].push_back(nPointPeriodic);
17867  nPointPeriodic++;
17868  }
17869  }
17870  }
17871 
17872  /*--- Sort the elements that must be replicated in the periodic boundary
17873  and delete the repeated elements ---*/
17874  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17875  if (CreateMirror[iPeriodic]) {
17876  sort( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end());
17877  IterElem = unique( PeriodicElem[iPeriodic].begin(), PeriodicElem[iPeriodic].end());
17878  PeriodicElem[iPeriodic].resize( IterElem - PeriodicElem[iPeriodic].begin() );
17879  }
17880  }
17881 
17882  /*--- Check all SEND points to see if they also lie on another boundary. ---*/
17883  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17884  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
17885 
17886  /*--- iPoint is a node that lies on the current marker. ---*/
17887  iPoint = vertex[iMarker][iVertex]->GetNode();
17888 
17889  /*--- Search through SEND points to check for iPoint. ---*/
17890  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17891  if (CreateMirror[iPeriodic]) {
17892 
17893  /*--- jPoint is the SEND point. ---*/
17894  for (iElem = 0; iElem < PeriodicPoint[iPeriodic][0].size(); iElem++) {
17895  jPoint = PeriodicPoint[iPeriodic][0][iElem];
17896 
17897  /*--- If the two match, then jPoint lies on this boundary.
17898  However, we are concerned with the new points, so we
17899  will store kPoint instead. ---*/
17900  if (iPoint == jPoint) {
17901 // kPoint = PeriodicPoint[iPeriodic][1][iElem];
17902 
17903  /*--- We also want the type of boundary element that this point
17904  was within, so that we know what type of element to add
17905  built from the new points. ---*/
17906  bool isJPoint, isPeriodic;
17907  for (jElem = 0; jElem < nElem_Bound[iMarker]; jElem++) {
17908  isJPoint = false; isPeriodic = false;
17909  for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) {
17910  if (bound[iMarker][jElem]->GetNode(iNode) == jPoint) isJPoint = true;
17911  if (PeriodicBC[bound[iMarker][jElem]->GetNode(iNode)]) isPeriodic = true;
17912  }
17913 
17914  /*--- If both points were found, store this element. ---*/
17915  if (isJPoint && isPeriodic) {
17916  OldBoundaryElems[iMarker].push_back(jElem);
17917  }
17918 
17919  }
17920 
17921  }
17922  }
17923  }
17924  }
17925  }
17926  }
17927 
17928  /*--- Sort the elements that must be added and remove duplicates. ---*/
17929  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17930  sort( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end());
17931  IterNewElem[iMarker] = unique( OldBoundaryElems[iMarker].begin(), OldBoundaryElems[iMarker].end());
17932  OldBoundaryElems[iMarker].resize( IterNewElem[iMarker] - OldBoundaryElems[iMarker].begin() );
17933  }
17934 
17935  /*--- Create the new boundary elements. Points making up these new
17936  elements must either be SEND/RECEIVE or periodic points. ---*/
17937  nNewElem_Bound = new unsigned long[nMarker];
17938  newBound = new CPrimalGrid**[nMarker];
17939  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
17940 
17941  nNewElem_Bound[iMarker] = OldBoundaryElems[iMarker].size();
17942  newBound[iMarker] = new CPrimalGrid*[nNewElem_Bound[iMarker]];
17943 
17944  /*--- Loop through all new elements to be added. ---*/
17945  for (iElem = 0; iElem < nNewElem_Bound[iMarker]; iElem++) {
17946  jElem = OldBoundaryElems[iMarker][iElem];
17947 
17948  /*--- Loop through all nodes of this element. ---*/
17949  for (iNode = 0; iNode < bound[iMarker][jElem]->GetnNodes(); iNode++) {
17950  pPoint = bound[iMarker][jElem]->GetNode(iNode);
17951 
17952  /*--- Check if this node is a send point. If so, the corresponding
17953  receive point will be used in making the new boundary element. ---*/
17954  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
17955  for (kElem = 0; kElem < PeriodicPoint[iPeriodic][0].size(); kElem++) {
17956  if (pPoint == PeriodicPoint[iPeriodic][0][kElem]) newNodes[iNode] = PeriodicPoint[iPeriodic][1][kElem];
17957  }
17958  }
17959 
17960  /*--- Check if this node is a periodic point. If so, the corresponding
17961  periodic point will be used in making the new boundary element. ---*/
17962  if (PeriodicBC[pPoint]) {
17963 
17964  /*--- Find the corresponding periodic point. ---*/
17965  for (jMarker = 0; jMarker < config->GetnMarker_All(); jMarker++) {
17966  if (config->GetMarker_All_KindBC(jMarker) == PERIODIC_BOUNDARY) {
17967  for (iVertex = 0; iVertex < nVertex[jMarker]; iVertex++) {
17968  if (pPoint == vertex[jMarker][iVertex]->GetNode()) {kMarker = jMarker; jVertex = iVertex;}
17969  }
17970  }
17971  }
17972  newNodes[iNode] = vertex[kMarker][jVertex]->GetDonorPoint();
17973  }
17974  }
17975 
17976  /*--- Now instantiate the new element. ---*/
17977  VTK_Type = bound[iMarker][jElem]->GetVTK_Type();
17978  switch(VTK_Type) {
17979  case LINE:
17980  newBound[iMarker][iElem] = new CLine(newNodes[0], newNodes[1],2);
17981  break;
17982  case TRIANGLE:
17983  newBound[iMarker][iElem] = new CTriangle(newNodes[0], newNodes[1], newNodes[2],3);
17984  break;
17985  case QUADRILATERAL:
17986  newBound[iMarker][iElem] = new CQuadrilateral(newNodes[0], newNodes[1], newNodes[2], newNodes[3],3);
17987  break;
17988  }
17989 
17990  }
17991  }
17992 
17993  delete [] PeriodicBC;
17994  delete [] CreateMirror;
17995 
17996 }
17997 
17999  su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord, *Normal;
18000  unsigned long Point_Normal, jPoint;
18001  unsigned short iNeigh, iMarker, iDim;
18002  unsigned long iPoint, iVertex;
18003 
18004  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
18005 
18006  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE &&
18007  config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY &&
18008  config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) {
18009 
18010  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
18011 
18012  iPoint = vertex[iMarker][iVertex]->GetNode();
18013  Normal = vertex[iMarker][iVertex]->GetNormal();
18014 
18015  /*--- Compute closest normal neighbor, note that the normal are oriented inwards ---*/
18016  Point_Normal = 0; cos_max = -1.0;
18017  for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) {
18018  jPoint = node[iPoint]->GetPoint(iNeigh);
18019  scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0;
18020  for (iDim = 0; iDim < nDim; iDim++) {
18021  diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim);
18022  scalar_prod += diff_coord*Normal[iDim];
18023  norm_vect += diff_coord*diff_coord;
18024  norm_Normal += Normal[iDim]*Normal[iDim];
18025  }
18026  norm_vect = sqrt(norm_vect);
18027  norm_Normal = sqrt(norm_Normal);
18028  cos_alpha = scalar_prod/(norm_vect*norm_Normal);
18029 
18030  /*--- Get maximum cosine ---*/
18031  if (cos_alpha >= cos_max) {
18032  Point_Normal = jPoint;
18033  cos_max = cos_alpha;
18034  }
18035  }
18036  vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal);
18037  }
18038  }
18039  }
18040 }
18041 
18043 
18044  bool loop_on;
18045  unsigned short iMarker = 0;
18046  su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL;
18047  unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0;
18048 
18049  /*--- Compute the total number of points on the near-field ---*/
18050  nVertex_Wall = 0;
18051  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
18052  if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) ||
18053  (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ||
18054  (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ||
18055  (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION))
18056  nVertex_Wall += nVertex[iMarker];
18057 
18058 
18059  /*--- Create an array with all the coordinates, points, pressures, face area,
18060  equivalent area, and nearfield weight ---*/
18061  Xcoord = new su2double[nVertex_Wall];
18062  Ycoord = new su2double[nVertex_Wall];
18063  if (nDim == 3) Zcoord = new su2double[nVertex_Wall];
18064  FaceArea = new su2double[nVertex_Wall];
18065 
18066  /*--- Copy the boundary information to an array ---*/
18067  iVertex_Wall = 0;
18068  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
18069  if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) ||
18070  (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ||
18071  (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ||
18072  (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION) )
18073  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
18074  iPoint = vertex[iMarker][iVertex]->GetNode();
18075  Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0);
18076  Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1);
18077  if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2);
18078  Face_Normal = vertex[iMarker][iVertex]->GetNormal();
18079  FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]);
18080  iVertex_Wall ++;
18081  }
18082 
18083 
18084  //vector<su2double> XCoordList;
18085  vector<su2double>::iterator IterXCoordList;
18086 
18087  for (iVertex = 0; iVertex < nVertex_Wall; iVertex++)
18088  XCoordList.push_back(Xcoord[iVertex]);
18089 
18090  sort( XCoordList.begin(), XCoordList.end());
18091  IterXCoordList = unique( XCoordList.begin(), XCoordList.end());
18092  XCoordList.resize( IterXCoordList - XCoordList.begin() );
18093 
18094  /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/
18095  Xcoord_plane.resize(XCoordList.size());
18096  Ycoord_plane.resize(XCoordList.size());
18097  if (nDim==3) Zcoord_plane.resize(XCoordList.size());
18098  FaceArea_plane.resize(XCoordList.size());
18099  Plane_points.resize(XCoordList.size());
18100 
18101 
18102  su2double dist_ratio;
18103  unsigned long iCoord;
18104 
18105  /*--- Distribute the values among the different PhiAngles ---*/
18106  for (iPoint = 0; iPoint < nPoint; iPoint++) {
18107  if (node[iPoint]->GetDomain()) {
18108  loop_on = true;
18109  for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) {
18110  dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]);
18111  if (dist_ratio >= 0 && dist_ratio <= 1.0) {
18112  if (dist_ratio <= 0.5) iCoord = ixCoord;
18113  else iCoord = ixCoord+1;
18114  Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) );
18115  Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) );
18116  if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) );
18117  FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume());
18118  Plane_points[iCoord].push_back(iPoint );
18119  loop_on = false;
18120  }
18121  }
18122  }
18123  }
18124 
18125  unsigned long auxPoint;
18126  /*--- Order the arrays in ascending values of y ---*/
18127  for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++)
18128  for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++)
18129  for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++)
18130  if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) {
18131  auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord;
18132  auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord;
18133  auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint;
18134  if (nDim==3) {
18135  auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord;
18136  }
18137  auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea;
18138  }
18139 
18140  /*--- Delete structures ---*/
18141  delete[] Xcoord; delete[] Ycoord;
18142  if (Zcoord != NULL) delete[] Zcoord;
18143  delete[] FaceArea;
18144 }
18145 
18147  unsigned short iMarker, icommas;
18148  unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0;
18149  su2double Sensitivity;
18150  bool *PointInDomain;
18151 
18152  nPointLocal = nPoint;
18153 #ifdef HAVE_MPI
18154  SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
18155 #else
18156  nPointGlobal = nPointLocal;
18157 #endif
18158 
18159  Point2Vertex = new unsigned long[nPointGlobal][2];
18160  PointInDomain = new bool[nPointGlobal];
18161 
18162  for (iPoint = 0; iPoint < nPointGlobal; iPoint ++)
18163  PointInDomain[iPoint] = false;
18164 
18165  for (iMarker = 0; iMarker < nMarker; iMarker++)
18166  if (config->GetMarker_All_DV(iMarker) == YES)
18167  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
18168 
18169  /*--- The sensitivity file uses the global numbering ---*/
18170  iPoint = node[vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex();
18171 
18172  if (vertex[iMarker][iVertex]->GetNode() < GetnPointDomain()) {
18173  Point2Vertex[iPoint][0] = iMarker;
18174  Point2Vertex[iPoint][1] = iVertex;
18175  PointInDomain[iPoint] = true;
18176  vertex[iMarker][iVertex]->SetAuxVar(0.0);
18177  }
18178  }
18179 
18180  /*--- Time-average any unsteady surface sensitivities ---*/
18181 
18182  unsigned long iExtIter, nExtIter;
18183  su2double delta_T, total_T;
18184  if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) {
18185  nExtIter = config->GetUnst_AdjointIter();
18186  delta_T = config->GetDelta_UnstTime();
18187  total_T = (su2double)nExtIter*delta_T;
18188  } else if (config->GetUnsteady_Simulation() == HARMONIC_BALANCE) {
18189 
18190  /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/
18191 
18192  su2double period = config->GetHarmonicBalance_Period();
18193  nExtIter = config->GetnTimeInstances();
18194  delta_T = period/(su2double)nExtIter;
18195  total_T = period;
18196 
18197  } else {
18198  nExtIter = 1;
18199  delta_T = 1.0;
18200  total_T = 1.0;
18201  }
18202 
18203  for (iExtIter = 0; iExtIter < nExtIter; iExtIter++) {
18204 
18205  /*--- Prepare to read surface sensitivity files (CSV) ---*/
18206 
18207  string text_line;
18208  ifstream Surface_file;
18209  char buffer[50];
18210  char cstr[MAX_STRING_SIZE];
18211  string surfadj_filename = config->GetSurfAdjCoeff_FileName();
18212  strcpy (cstr, surfadj_filename.c_str());
18213 
18214  /*--- Write file name with extension if unsteady or steady ---*/
18215  if (config->GetUnsteady_Simulation() == HARMONIC_BALANCE)
18216  SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter));
18217 
18218  if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) ||
18219  (config->GetUnsteady_Simulation() == HARMONIC_BALANCE)) {
18220  if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter));
18221  if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter));
18222  if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter));
18223  if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter));
18224  if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter));
18225  }
18226  else
18227  SPRINTF (buffer, ".csv");
18228 
18229  strcat (cstr, buffer);
18230 
18231  /*--- Read the sensitivity file ---*/
18232 
18233  string::size_type position;
18234 
18235  Surface_file.open(cstr, ios::in);
18236 
18237  /*--- Read extra inofmration ---*/
18238 
18239  getline(Surface_file, text_line);
18240  text_line.erase (0,9);
18241  su2double AoASens = atof(text_line.c_str());
18242  config->SetAoA_Sens(AoASens);
18243 
18244  /*--- File header ---*/
18245 
18246  getline(Surface_file, text_line);
18247 
18248  while (getline(Surface_file, text_line)) {
18249  for (icommas = 0; icommas < 50; icommas++) {
18250  position = text_line.find( ",", 0 );
18251  if (position!=string::npos) text_line.erase (position,1);
18252  }
18253  stringstream point_line(text_line);
18254  point_line >> iPoint >> Sensitivity;
18255 
18256  if (PointInDomain[iPoint]) {
18257 
18258  /*--- Find the vertex for the Point and Marker ---*/
18259 
18260  iMarker = Point2Vertex[iPoint][0];
18261  iVertex = Point2Vertex[iPoint][1];
18262 
18263  /*--- Increment the auxiliary variable with the contribution of
18264  this unsteady timestep. For steady problems, this reduces to
18265  a single sensitivity value multiplied by 1.0. ---*/
18266 
18267  vertex[iMarker][iVertex]->AddAuxVar(Sensitivity*(delta_T/total_T));
18268  }
18269 
18270  }
18271  Surface_file.close();
18272  }
18273 
18274  delete[] Point2Vertex;
18275  delete[] PointInDomain;
18276 
18277 }
18278 
18280  unsigned short iMarker, icommas;
18281  unsigned long iVertex, iPoint, iPoint_Local, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0;
18282  su2double Sensitivity_Transp, dummy;
18283  bool *PointInDomain;
18284 
18285 #ifdef HAVE_MPI
18286  int rank = MASTER_NODE;
18287  int size = SINGLE_NODE;
18288  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
18289  MPI_Comm_size(MPI_COMM_WORLD, &size);
18290 #endif
18291 
18292  nPointLocal = nPoint;
18293 #ifdef HAVE_MPI
18294  SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
18295 #else
18296  nPointGlobal = nPointLocal;
18297 #endif
18298 
18299  Point2Vertex = new unsigned long[nPointGlobal][2];
18300  PointInDomain = new bool[nPointGlobal];
18301 
18302  for (iPoint = 0; iPoint < nPointGlobal; iPoint ++)
18303  PointInDomain[iPoint] = false;
18304 
18305  for (iMarker = 0; iMarker < nMarker; iMarker++){
18306  if (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION){
18307  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
18308 
18309  /*--- The sensitivity file uses the global numbering ---*/
18310  iPoint = node[vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex();
18311 
18312  if (vertex[iMarker][iVertex]->GetNode() < GetnPointDomain()) {
18313  Point2Vertex[iPoint][0] = iMarker;
18314  Point2Vertex[iPoint][1] = iVertex;
18315  PointInDomain[iPoint] = true;
18316  vertex[iMarker][iVertex]->SetAuxTransp(0.0);
18317  }
18318  }
18319  }
18320  }
18321 
18322  /*--- Time-average any unsteady surface sensitivities ---*/
18323 
18324  unsigned long iExtIter, nExtIter;
18325  su2double delta_T, total_T;
18326  if (config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) {
18327  nExtIter = config->GetUnst_AdjointIter();
18328  delta_T = config->GetDelta_UnstTime();
18329  total_T = (su2double)nExtIter*delta_T;
18330  } else if (config->GetUnsteady_Simulation() == HARMONIC_BALANCE) {
18331 
18332  /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/
18333 
18334  su2double period = config->GetHarmonicBalance_Period();
18335  nExtIter = config->GetnTimeInstances();
18336  delta_T = period/(su2double)nExtIter;
18337  total_T = period;
18338 
18339  } else {
18340  nExtIter = 1;
18341  delta_T = 1.0;
18342  total_T = 1.0;
18343  }
18344 
18345  for (iExtIter = 0; iExtIter < nExtIter; iExtIter++) {
18346 
18347  /*--- Prepare to read surface sensitivity files (CSV) ---*/
18348 
18349  string text_line;
18350  ifstream Surface_file;
18351  char buffer[50];
18352  char cstr[MAX_STRING_SIZE];
18353  string surfadj_filename = config->GetSurfAdjCoeff_FileName();
18354  strcpy (cstr, surfadj_filename.c_str());
18355 
18356  /*--- Write file name with extension if unsteady or steady ---*/
18357  if (config->GetUnsteady_Simulation() == HARMONIC_BALANCE)
18358  SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter));
18359 
18360  if ((config->GetUnsteady_Simulation() && config->GetWrt_Unsteady()) ||
18361  (config->GetUnsteady_Simulation() == HARMONIC_BALANCE)) {
18362  if ((SU2_TYPE::Int(iExtIter) >= 0) && (SU2_TYPE::Int(iExtIter) < 10)) SPRINTF (buffer, "_0000%d.csv", SU2_TYPE::Int(iExtIter));
18363  if ((SU2_TYPE::Int(iExtIter) >= 10) && (SU2_TYPE::Int(iExtIter) < 100)) SPRINTF (buffer, "_000%d.csv", SU2_TYPE::Int(iExtIter));
18364  if ((SU2_TYPE::Int(iExtIter) >= 100) && (SU2_TYPE::Int(iExtIter) < 1000)) SPRINTF (buffer, "_00%d.csv", SU2_TYPE::Int(iExtIter));
18365  if ((SU2_TYPE::Int(iExtIter) >= 1000) && (SU2_TYPE::Int(iExtIter) < 10000)) SPRINTF (buffer, "_0%d.csv", SU2_TYPE::Int(iExtIter));
18366  if (SU2_TYPE::Int(iExtIter) >= 10000) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iExtIter));
18367  }
18368  else
18369  SPRINTF (buffer, ".csv");
18370 
18371  strcat (cstr, buffer);
18372 
18373  /*--- Read the sensitivity file ---*/
18374 
18375  string::size_type position;
18376 
18377  Surface_file.open(cstr, ios::in);
18378 
18379  /*--- Read extra inofmration ---*/
18380 
18381  getline(Surface_file, text_line);
18382  text_line.erase (0,9);
18383  su2double AoASens = atof(text_line.c_str());
18384  config->SetAoA_Sens(AoASens);
18385 
18386  /*--- File header ---*/
18387 
18388  getline(Surface_file, text_line);
18389 
18390  while (getline(Surface_file, text_line)) {
18391  for (icommas = 0; icommas < 50; icommas++) {
18392  position = text_line.find( ",", 0 );
18393  if (position!=string::npos) text_line.erase (position,1);
18394  }
18395  stringstream point_line(text_line);
18396  point_line >> iPoint >> dummy;
18397 
18398  /*--- Skip adjoint vars, coords, and mesh sens ---*/
18399  for(unsigned short iVar = 0; iVar < nDim+2; iVar++){
18400  point_line >> dummy;
18401  }
18402  for(unsigned short iVar = 0; iVar < 2*nDim; iVar++){
18403  point_line >> dummy;
18404  }
18405 
18406  if (PointInDomain[iPoint]) {
18407 
18408  /*--- Find the vertex for the Point and Marker ---*/
18409 
18410  iMarker = Point2Vertex[iPoint][0];
18411  iVertex = Point2Vertex[iPoint][1];
18412 
18413  /*--- Increment the auxiliary transpiration variable with the contribution of
18414  this unsteady timestep. For steady problems, this reduces to
18415  a single sensitivity value multiplied by 1.0. ---*/
18416 
18417  point_line >> Sensitivity_Transp;
18418 
18419  if(config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION)
18420  vertex[iMarker][iVertex]->AddAuxTransp(Sensitivity_Transp*(delta_T/total_T));
18421  }
18422 
18423  }
18424  Surface_file.close();
18425  }
18426 
18427  delete[] Point2Vertex;
18428  delete[] PointInDomain;
18429 
18430 }
18431 
18433 
18434  ifstream restart_file;
18435  string filename = config->GetSolution_AdjFileName();
18436  bool compressible = (config->GetKind_Regime() == COMPRESSIBLE);
18437  bool incompressible = (config->GetKind_Regime() == INCOMPRESSIBLE);
18438  bool sst = config->GetKind_Turb_Model() == SST;
18439  bool sa = (config->GetKind_Turb_Model() == SA) || (config->GetKind_Turb_Model() == SA_NEG);
18440  bool grid_movement = config->GetGrid_Movement();
18441  bool frozen_visc = config->GetFrozen_Visc_Disc();
18442  su2double Sens, dull_val, AoASens;
18443  unsigned short nExtIter, iDim;
18444  unsigned long iPoint, index;
18445  string::size_type position;
18446  int counter = 0;
18447 
18448  Sensitivity = new su2double[nPoint*nDim];
18449 
18450  if (config->GetUnsteady_Simulation()) {
18451  nExtIter = config->GetnExtIter();
18452  }else {
18453  nExtIter = 1;
18454  }
18455 
18456  if (rank == MASTER_NODE)
18457  cout << "Reading in sensitivity at iteration " << nExtIter-1 << "."<< endl;
18458 
18459  unsigned short skipVar = nDim, skipMult = 1;
18460 
18461  if (incompressible) { skipVar += skipMult*(nDim+2); }
18462  if (compressible) { skipVar += skipMult*(nDim+2); }
18463  if (sst && !frozen_visc) { skipVar += skipMult*2;}
18464  if (sa && !frozen_visc) { skipVar += skipMult*1;}
18465  if (grid_movement) { skipVar += nDim;}
18466 
18467  /*--- Read all lines in the restart file ---*/
18468  long iPoint_Local; unsigned long iPoint_Global = 0; string text_line;
18469 
18470 
18471  for (iPoint = 0; iPoint < nPoint; iPoint++) {
18472  for (iDim = 0; iDim < nDim; iDim++) {
18473  Sensitivity[iPoint*nDim+iDim] = 0.0;
18474  }
18475  }
18476 
18477  iPoint_Global = 0;
18478 
18479  filename = config->GetSolution_AdjFileName();
18480 
18481  filename = config->GetObjFunc_Extension(filename);
18482 
18483  if (config->GetUnsteady_Simulation()) {
18484  filename = config->GetUnsteady_FileName(filename, nExtIter-1);
18485  }
18486 
18487  if (config->GetnZone() > 1){
18488  filename = config->GetMultizone_FileName(filename, config->GetiZone());
18489  }
18490 
18491  if (config->GetRead_Binary_Restart()) {
18492 
18493  char str_buf[CGNS_STRING_SIZE], fname[100];
18494  unsigned short iVar;
18495  strcpy(fname, filename.c_str());
18496  int nRestart_Vars = 5, nFields;
18497  int *Restart_Vars = new int[5];
18498  passivedouble *Restart_Data = NULL;
18499  int Restart_Iter = 0;
18500  passivedouble Restart_Meta_Passive[8] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
18501  su2double Restart_Meta[8] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
18502 
18503 #ifndef HAVE_MPI
18504 
18505  /*--- Serial binary input. ---*/
18506 
18507  FILE *fhw;
18508  fhw = fopen(fname,"rb");
18509  size_t ret;
18510 
18511  /*--- Error check for opening the file. ---*/
18512 
18513  if (!fhw) {
18514  SU2_MPI::Error(string("Unable to open SU2 restart file ") + fname, CURRENT_FUNCTION);
18515  }
18516 
18517  /*--- First, read the number of variables and points. ---*/
18518 
18519  ret = fread(Restart_Vars, sizeof(int), nRestart_Vars, fhw);
18520  if (ret != (unsigned long)nRestart_Vars) {
18521  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18522  }
18523 
18524  /*--- Check that this is an SU2 binary file. SU2 binary files
18525  have the hex representation of "SU2" as the first int in the file. ---*/
18526 
18527  if (Restart_Vars[0] != 535532) {
18528  SU2_MPI::Error(string("File ") + string(fname) + string(" is not a binary SU2 restart file.\n") +
18529  string("SU2 reads/writes binary restart files by default.\n") +
18530  string("Note that backward compatibility for ASCII restart files is\n") +
18531  string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION);
18532  }
18533 
18534  /*--- Store the number of fields for simplicity. ---*/
18535 
18536  nFields = Restart_Vars[1];
18537 
18538  /*--- Read the variable names from the file. Note that we are adopting a
18539  fixed length of 33 for the string length to match with CGNS. This is
18540  needed for when we read the strings later. We pad the beginning of the
18541  variable string vector with the Point_ID tag that wasn't written. ---*/
18542 
18543  config->fields.push_back("Point_ID");
18544  for (iVar = 0; iVar < nFields; iVar++) {
18545  ret = fread(str_buf, sizeof(char), CGNS_STRING_SIZE, fhw);
18546  if (ret != (unsigned long)CGNS_STRING_SIZE) {
18547  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18548  }
18549  config->fields.push_back(str_buf);
18550  }
18551 
18552  /*--- For now, create a temp 1D buffer to read the data from file. ---*/
18553 
18554  Restart_Data = new passivedouble[nFields*GetnPointDomain()];
18555 
18556  /*--- Read in the data for the restart at all local points. ---*/
18557 
18558  ret = fread(Restart_Data, sizeof(passivedouble), nFields*GetnPointDomain(), fhw);
18559  if (ret != (unsigned long)nFields*GetnPointDomain()) {
18560  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18561  }
18562 
18563  /*--- Compute (negative) displacements and grab the metadata. ---*/
18564 
18565  fseek(fhw,-(sizeof(int) + 8*sizeof(passivedouble)), SEEK_END);
18566 
18567  /*--- Read the external iteration. ---*/
18568 
18569  ret = fread(&Restart_Iter, sizeof(int), 1, fhw);
18570  if (ret != 1) {
18571  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18572  }
18573 
18574  /*--- Read the metadata. ---*/
18575 
18576  ret = fread(Restart_Meta_Passive, sizeof(passivedouble), 8, fhw);
18577  if (ret != 8) {
18578  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18579  }
18580 
18581  /*--- Close the file. ---*/
18582 
18583  fclose(fhw);
18584 
18585 #else
18586 
18587  /*--- Parallel binary input using MPI I/O. ---*/
18588 
18589  MPI_File fhw;
18590  SU2_MPI::Status status;
18591  MPI_Datatype etype, filetype;
18592  MPI_Offset disp;
18593  unsigned long iPoint_Global, iChar;
18594  string field_buf;
18595 
18596  int ierr;
18597 
18598  /*--- All ranks open the file using MPI. ---*/
18599 
18600  ierr = MPI_File_open(MPI_COMM_WORLD, fname, MPI_MODE_RDONLY, MPI_INFO_NULL, &fhw);
18601 
18602  /*--- Error check opening the file. ---*/
18603 
18604  if (ierr) {
18605  SU2_MPI::Error(string("Unable to open SU2 restart file ") + string(fname), CURRENT_FUNCTION);
18606  }
18607 
18608  /*--- First, read the number of variables and points (i.e., cols and rows),
18609  which we will need in order to read the file later. Also, read the
18610  variable string names here. Only the master rank reads the header. ---*/
18611 
18612  if (rank == MASTER_NODE)
18613  MPI_File_read(fhw, Restart_Vars, nRestart_Vars, MPI_INT, MPI_STATUS_IGNORE);
18614 
18615  /*--- Broadcast the number of variables to all procs and store clearly. ---*/
18616 
18617  SU2_MPI::Bcast(Restart_Vars, nRestart_Vars, MPI_INT, MASTER_NODE, MPI_COMM_WORLD);
18618 
18619  /*--- Check that this is an SU2 binary file. SU2 binary files
18620  have the hex representation of "SU2" as the first int in the file. ---*/
18621 
18622  if (Restart_Vars[0] != 535532) {
18623 
18624  SU2_MPI::Error(string("File ") + string(fname) + string(" is not a binary SU2 restart file.\n") +
18625  string("SU2 reads/writes binary restart files by default.\n") +
18626  string("Note that backward compatibility for ASCII restart files is\n") +
18627  string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION);
18628  }
18629 
18630  /*--- Store the number of fields for simplicity. ---*/
18631 
18632  nFields = Restart_Vars[1];
18633 
18634  /*--- Read the variable names from the file. Note that we are adopting a
18635  fixed length of 33 for the string length to match with CGNS. This is
18636  needed for when we read the strings later. ---*/
18637 
18638  char *mpi_str_buf = new char[nFields*CGNS_STRING_SIZE];
18639  if (rank == MASTER_NODE) {
18640  disp = nRestart_Vars*sizeof(int);
18641  MPI_File_read_at(fhw, disp, mpi_str_buf, nFields*CGNS_STRING_SIZE,
18643  }
18644 
18645  /*--- Broadcast the string names of the variables. ---*/
18646 
18647  SU2_MPI::Bcast(mpi_str_buf, nFields*CGNS_STRING_SIZE, MPI_CHAR,
18649 
18650  /*--- Now parse the string names and load into the config class in case
18651  we need them for writing visualization files (SU2_SOL). ---*/
18652 
18653  config->fields.push_back("Point_ID");
18654  for (iVar = 0; iVar < nFields; iVar++) {
18655  index = iVar*CGNS_STRING_SIZE;
18656  field_buf.append("\"");
18657  for (iChar = 0; iChar < (unsigned long)CGNS_STRING_SIZE; iChar++) {
18658  str_buf[iChar] = mpi_str_buf[index + iChar];
18659  }
18660  field_buf.append(str_buf);
18661  field_buf.append("\"");
18662  config->fields.push_back(field_buf.c_str());
18663  field_buf.clear();
18664  }
18665 
18666  /*--- Free string buffer memory. ---*/
18667 
18668  delete [] mpi_str_buf;
18669 
18670  /*--- We're writing only su2doubles in the data portion of the file. ---*/
18671 
18672  etype = MPI_DOUBLE;
18673 
18674  /*--- We need to ignore the 4 ints describing the nVar_Restart and nPoints,
18675  along with the string names of the variables. ---*/
18676 
18677  disp = nRestart_Vars*sizeof(int) + CGNS_STRING_SIZE*nFields*sizeof(char);
18678 
18679  /*--- Define a derived datatype for this rank's set of non-contiguous data
18680  that will be placed in the restart. Here, we are collecting each one of the
18681  points which are distributed throughout the file in blocks of nVar_Restart data. ---*/
18682 
18683  int *blocklen = new int[GetnPointDomain()];
18684  int *displace = new int[GetnPointDomain()];
18685 
18686  counter = 0;
18687  for (iPoint_Global = 0; iPoint_Global < GetGlobal_nPointDomain(); iPoint_Global++ ) {
18688  if (GetGlobal_to_Local_Point(iPoint_Global) > -1) {
18689  blocklen[counter] = nFields;
18690  displace[counter] = iPoint_Global*nFields;
18691  counter++;
18692  }
18693  }
18694  MPI_Type_indexed(GetnPointDomain(), blocklen, displace, MPI_DOUBLE, &filetype);
18695  MPI_Type_commit(&filetype);
18696 
18697  /*--- Set the view for the MPI file write, i.e., describe the location in
18698  the file that this rank "sees" for writing its piece of the restart file. ---*/
18699 
18700  MPI_File_set_view(fhw, disp, etype, filetype, (char*)"native", MPI_INFO_NULL);
18701 
18702  /*--- For now, create a temp 1D buffer to read the data from file. ---*/
18703 
18704  Restart_Data = new passivedouble[nFields*GetnPointDomain()];
18705 
18706  /*--- Collective call for all ranks to read from their view simultaneously. ---*/
18707 
18708  MPI_File_read_all(fhw, Restart_Data, nFields*GetnPointDomain(), MPI_DOUBLE, &status);
18709 
18710  /*--- Free the derived datatype. ---*/
18711 
18712  MPI_Type_free(&filetype);
18713 
18714  /*--- Reset the file view before writing the metadata. ---*/
18715 
18716  MPI_File_set_view(fhw, 0, MPI_BYTE, MPI_BYTE, (char*)"native", MPI_INFO_NULL);
18717 
18718  /*--- Access the metadata. ---*/
18719 
18720  if (rank == MASTER_NODE) {
18721 
18722  /*--- External iteration. ---*/
18723  disp = (nRestart_Vars*sizeof(int) + nFields*CGNS_STRING_SIZE*sizeof(char) +
18724  nFields*Restart_Vars[2]*sizeof(passivedouble));
18725  MPI_File_read_at(fhw, disp, &Restart_Iter, 1, MPI_INT, MPI_STATUS_IGNORE);
18726 
18727  /*--- Additional doubles for AoA, AoS, etc. ---*/
18728 
18729  disp = (nRestart_Vars*sizeof(int) + nFields*CGNS_STRING_SIZE*sizeof(char) +
18730  nFields*Restart_Vars[2]*sizeof(passivedouble) + 1*sizeof(int));
18731  MPI_File_read_at(fhw, disp, Restart_Meta_Passive, 8, MPI_DOUBLE, MPI_STATUS_IGNORE);
18732 
18733  }
18734 
18735  /*--- Communicate metadata. ---*/
18736 
18737  SU2_MPI::Bcast(&Restart_Iter, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD);
18738 
18739  /*--- Copy to a su2double structure (because of the SU2_MPI::Bcast
18740  doesn't work with passive data)---*/
18741 
18742  for (unsigned short iVar = 0; iVar < 8; iVar++)
18743  Restart_Meta[iVar] = Restart_Meta_Passive[iVar];
18744 
18746 
18747  /*--- All ranks close the file after writing. ---*/
18748 
18749  MPI_File_close(&fhw);
18750 
18751  delete [] blocklen;
18752  delete [] displace;
18753 
18754 #endif
18755 
18756  /*--- Load the data from the binary restart. ---*/
18757 
18758  counter = 0;
18759  for (iPoint_Global = 0; iPoint_Global < GetGlobal_nPointDomain(); iPoint_Global++ ) {
18760 
18761  /*--- Retrieve local index. If this node from the restart file lives
18762  on the current processor, we will load and instantiate the vars. ---*/
18763 
18764  iPoint_Local = GetGlobal_to_Local_Point(iPoint_Global);
18765 
18766  if (iPoint_Local > -1) {
18767 
18768  /*--- We need to store this point's data, so jump to the correct
18769  offset in the buffer of data from the restart file and load it. ---*/
18770 
18771  index = counter*nFields + skipVar;
18772  for (iDim = 0; iDim < nDim; iDim++) Sensitivity[iPoint_Local*nDim+iDim] = Restart_Data[index+iDim];
18773 
18774  /*--- Increment the overall counter for how many points have been loaded. ---*/
18775  counter++;
18776  }
18777  }
18778 
18779  /*--- Lastly, load the AoA sensitivity from the binary metadata. ---*/
18780 
18781  config->SetAoA_Sens(Restart_Meta[4]);
18782 
18783  } else {
18784 
18785  /*--- First, check that this is not a binary restart file. ---*/
18786 
18787  char fname[100];
18788  strcpy(fname, filename.c_str());
18789  int magic_number;
18790 
18791 #ifndef HAVE_MPI
18792 
18793  /*--- Serial binary input. ---*/
18794 
18795  FILE *fhw;
18796  fhw = fopen(fname,"rb");
18797  size_t ret;
18798 
18799  /*--- Error check for opening the file. ---*/
18800 
18801  if (!fhw) {
18802  SU2_MPI::Error(string("Unable to open SU2 restart file ") + string(fname), CURRENT_FUNCTION);
18803  }
18804 
18805  /*--- Attempt to read the first int, which should be our magic number. ---*/
18806 
18807  ret = fread(&magic_number, sizeof(int), 1, fhw);
18808  if (ret != 1) {
18809  SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION);
18810  }
18811 
18812  /*--- Check that this is an SU2 binary file. SU2 binary files
18813  have the hex representation of "SU2" as the first int in the file. ---*/
18814 
18815  if (magic_number == 535532) {
18816  SU2_MPI::Error(string("File ") + string(fname) + string(" is a binary SU2 restart file, expected ASCII.\n") +
18817  string("SU2 reads/writes binary restart files by default.\n") +
18818  string("Note that backward compatibility for ASCII restart files is\n") +
18819  string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION);
18820  }
18821 
18822  fclose(fhw);
18823 
18824 #else
18825 
18826  /*--- Parallel binary input using MPI I/O. ---*/
18827 
18828  MPI_File fhw;
18829  int ierr;
18830 
18831  /*--- All ranks open the file using MPI. ---*/
18832 
18833  ierr = MPI_File_open(MPI_COMM_WORLD, fname, MPI_MODE_RDONLY, MPI_INFO_NULL, &fhw);
18834 
18835  /*--- Error check opening the file. ---*/
18836 
18837  if (ierr) {
18838  SU2_MPI::Error(string("Unable to open SU2 restart file ") + string(fname), CURRENT_FUNCTION);
18839  }
18840 
18841  /*--- Have the master attempt to read the magic number. ---*/
18842 
18843  if (rank == MASTER_NODE)
18844  MPI_File_read(fhw, &magic_number, 1, MPI_INT, MPI_STATUS_IGNORE);
18845 
18846  /*--- Broadcast the number of variables to all procs and store clearly. ---*/
18847 
18848  SU2_MPI::Bcast(&magic_number, 1, MPI_INT, MASTER_NODE, MPI_COMM_WORLD);
18849 
18850  /*--- Check that this is an SU2 binary file. SU2 binary files
18851  have the hex representation of "SU2" as the first int in the file. ---*/
18852 
18853  if (magic_number == 535532) {
18854 
18855  SU2_MPI::Error(string("File ") + string(fname) + string(" is a binary SU2 restart file, expected ASCII.\n") +
18856  string("SU2 reads/writes binary restart files by default.\n") +
18857  string("Note that backward compatibility for ASCII restart files is\n") +
18858  string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION);
18859  }
18860 
18861  MPI_File_close(&fhw);
18862 
18863 #endif
18864 
18865  restart_file.open(filename.data(), ios::in);
18866  if (restart_file.fail()) {
18867  SU2_MPI::Error(string("There is no adjoint restart file ") + filename, CURRENT_FUNCTION);
18868  }
18869 
18870  /*--- The first line is the header ---*/
18871 
18872  getline (restart_file, text_line);
18873 
18874  for (iPoint_Global = 0; iPoint_Global < GetGlobal_nPointDomain(); iPoint_Global++ ) {
18875 
18876  getline (restart_file, text_line);
18877 
18878  istringstream point_line(text_line);
18879 
18880  /*--- Retrieve local index. If this node from the restart file lives
18881  on the current processor, we will load and instantiate the vars. ---*/
18882 
18883  iPoint_Local = GetGlobal_to_Local_Point(iPoint_Global);
18884 
18885  if (iPoint_Local > -1) {
18886 
18887  point_line >> index;
18888  for (iDim = 0; iDim < skipVar; iDim++) { point_line >> dull_val;}
18889  for (iDim = 0; iDim < nDim; iDim++) {
18890  point_line >> Sens;
18891  Sensitivity[iPoint_Local*nDim+iDim] = Sens;
18892  }
18893  }
18894 
18895  }
18896 
18897  /*--- Read AoA sensitivity ---*/
18898 
18899  while (getline (restart_file, text_line)) {
18900  position = text_line.find ("SENS_AOA=",0);
18901  if (position != string::npos) {
18902  text_line.erase (0,9); AoASens = atof(text_line.c_str());
18903  config->SetAoA_Sens(AoASens);
18904  }
18905  }
18906 
18907  restart_file.close();
18908 
18909  }
18910 
18911 }
18912 
18914 
18915  bool isPeriodic = false;
18916  unsigned long iVertex;
18917  unsigned short iMarker, RotationKind, nPeriodicR = 0, nPeriodicS = 0;
18918 
18919  /*--- Check for the presence of any periodic BCs ---*/
18920 
18921  for (iMarker = 0; iMarker < nMarker; iMarker++) {
18922  if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) {
18923  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
18924  RotationKind = vertex[iMarker][iVertex]->GetRotation_Type();
18925  if (RotationKind > 0) nPeriodicS++;
18926  }
18927  }
18928  }
18929 #ifndef HAVE_MPI
18930  nPeriodicR = nPeriodicS;
18931 #else
18932  SU2_MPI::Allreduce(&nPeriodicS, &nPeriodicR, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD);
18933 #endif
18934  if (nPeriodicR != 0) isPeriodic = true;
18935 
18936  if (isPeriodic && (config->GetnMGLevels() > 0)) {
18937  if (rank == MASTER_NODE)
18938  cout << "WARNING: Periodicity has been detected. Disabling multigrid. "<< endl;
18939  config->SetMGLevels(0);
18940  }
18941 
18942 }
18943 
18944 su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
18945 
18946  unsigned long iVertex, jVertex, n, Trailing_Point, Leading_Point;
18947  su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, zp1, zpn, MaxThickness_Value = 0, Thickness, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, MaxDistance, Distance, AoA;
18948  vector<su2double> Xcoord, Ycoord, Zcoord, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_;
18949 
18950  /*--- Find the leading and trailing edges and compute the angle of attack ---*/
18951 
18952  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
18953  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
18954  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
18955  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
18956  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
18957 
18958  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
18959  }
18960 
18961  AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER;
18962 
18963  /*--- Translate to the origin ---*/
18964 
18965  Xcoord_Trailing = Xcoord_Airfoil[0];
18966  Ycoord_Trailing = Ycoord_Airfoil[0];
18967  Zcoord_Trailing = Zcoord_Airfoil[0];
18968 
18969  for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) {
18970  Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing);
18971  Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing);
18972  Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing);
18973  }
18974 
18975  /*--- Rotate the airfoil ---*/
18976 
18977  ValCos = cos(AoA*PI_NUMBER/180.0);
18978  ValSin = sin(AoA*PI_NUMBER/180.0);
18979 
18980  for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) {
18981  XValue = Xcoord_Airfoil_[iVertex];
18982  ZValue = Zcoord_Airfoil_[iVertex];
18983  Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin;
18984  Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin;
18985  }
18986 
18987  /*--- Identify upper and lower side, and store the value of the normal --*/
18988 
18989  for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) {
18990  Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1];
18991  Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1];
18992  Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1];
18993  Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0));
18994 
18995  Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length;
18996 
18997  BiNormal[0] = Plane_Normal[0];
18998  BiNormal[1] = Plane_Normal[1];
18999  BiNormal[2] = Plane_Normal[2];
19000  Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0));
19001  BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length;
19002 
19003  Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1];
19004  Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2];
19005  Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0];
19006 
19007  Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]);
19008 
19009  unsigned short index = 2;
19010 
19011  /*--- Removing the trailing edge from list of points that we are going to use in the interpolation,
19012  to be sure that a blunt trailing edge do not affect the interpolation ---*/
19013 
19014  if ((Normal[index] >= 0.0) && (fabs(Xcoord_Airfoil_[iVertex]) > MaxDistance*0.01)) {
19015  Xcoord.push_back(Xcoord_Airfoil_[iVertex]);
19016  Ycoord.push_back(Ycoord_Airfoil_[iVertex]);
19017  Zcoord.push_back(Zcoord_Airfoil_[iVertex]);
19018  }
19019 
19020  }
19021 
19022  /*--- Order the arrays using the X component ---*/
19023 
19024  for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) {
19025  for (jVertex = 0; jVertex < Xcoord.size() - 1 - iVertex; jVertex++) {
19026  if (Xcoord[jVertex] > Xcoord[jVertex+1]) {
19027  auxXCoord = Xcoord[jVertex]; Xcoord[jVertex] = Xcoord[jVertex+1]; Xcoord[jVertex+1] = auxXCoord;
19028  auxYCoord = Ycoord[jVertex]; Ycoord[jVertex] = Ycoord[jVertex+1]; Ycoord[jVertex+1] = auxYCoord;
19029  auxZCoord = Zcoord[jVertex]; Zcoord[jVertex] = Zcoord[jVertex+1]; Zcoord[jVertex+1] = auxZCoord;
19030  }
19031  }
19032  }
19033 
19034  n = Xcoord.size();
19035  if (n > 1) {
19036  zp1 = (Zcoord[1]-Zcoord[0])/(Xcoord[1]-Xcoord[0]);
19037  zpn = (Zcoord[n-1]-Zcoord[n-2])/(Xcoord[n-1]-Xcoord[n-2]);
19038  Z2coord.resize(n+1);
19039  SetSpline(Xcoord, Zcoord, n, zp1, zpn, Z2coord);
19040 
19041  /*--- Compute the thickness (we add a fabs because we can not guarantee the
19042  right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/
19043 
19044  MaxThickness_Value = 0.0;
19045  for (iVertex = 0; iVertex < Xcoord_Airfoil_.size(); iVertex++) {
19046  if (Zcoord_Normal[iVertex] < 0.0) {
19047  Thickness = fabs(Zcoord_Airfoil_[iVertex] - GetSpline(Xcoord, Zcoord, Z2coord, n, Xcoord_Airfoil_[iVertex]));
19048  if (Thickness > MaxThickness_Value) { MaxThickness_Value = Thickness; }
19049  }
19050  }
19051  }
19052  else { MaxThickness_Value = 0.0; }
19053 
19054  return MaxThickness_Value;
19055 
19056 }
19057 
19059  su2double *LeadingEdge_i, su2double *TrailingEdge_i) {
19060 
19061  // su2double Dihedral_Leading = atan((LeadingEdge_i[2] - LeadingEdge_im1[2]) / (LeadingEdge_i[1] - LeadingEdge_im1[1]))*180/PI_NUMBER;
19062  su2double Dihedral_Trailing = atan((TrailingEdge_i[2] - TrailingEdge_im1[2]) / (TrailingEdge_i[1] - TrailingEdge_im1[1]))*180/PI_NUMBER;
19063 
19064  // su2double Dihedral = 0.5*(Dihedral_Leading + Dihedral_Trailing);
19065 
19066  return Dihedral_Trailing;
19067 
19068 }
19069 
19071  su2double *LeadingEdge_i, su2double *TrailingEdge_i,
19072  su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1) {
19073 
19074  su2double A[2], B[2], C[2], BC[2], AB[2], AC[2], BC_MOD, AB_MOD, AC_MOD, AB_CROSS_AC;
19075 
19076  // A[0] = LeadingEdge_im1[1]; A[1] = LeadingEdge_im1[2];
19077  // B[0] = LeadingEdge_i[1]; B[1] = LeadingEdge_i[2];
19078  // C[0] = LeadingEdge_ip1[1]; C[1] = LeadingEdge_ip1[2];
19079 
19080  // BC[0] = C[0] - B[0]; BC[1] = C[1] - B[1];
19081  // AB[0] = B[0] - A[0]; AB[1] = B[1] - A[1];
19082  // AC[0] = C[0] - A[0]; AC[1] = C[1] - A[1];
19083  // BC_MOD = sqrt(BC[0]*BC[0] + BC[1]*BC[1] );
19084  // AB_MOD = sqrt(AB[0]*AB[0] + AB[1]*AB[1] );
19085  // AC_MOD = sqrt(AC[0]*AC[0] + AC[1]*AC[1] );
19086  // AB_CROSS_AC = AB[0]* AC[1] - AB[1]* AC[0];
19087 
19088  // su2double Curvature_Leading = fabs(1.0/(0.5*BC_MOD*AB_MOD*AC_MOD/AB_CROSS_AC));
19089 
19090  A[0] = TrailingEdge_im1[1]; A[1] = TrailingEdge_im1[2];
19091  B[0] = TrailingEdge_i[1]; B[1] = TrailingEdge_i[2];
19092  C[0] = TrailingEdge_ip1[1]; C[1] = TrailingEdge_ip1[2];
19093 
19094  BC[0] = C[0] - B[0]; BC[1] = C[1] - B[1];
19095  AB[0] = B[0] - A[0]; AB[1] = B[1] - A[1];
19096  AC[0] = C[0] - A[0]; AC[1] = C[1] - A[1];
19097  BC_MOD = sqrt(BC[0]*BC[0] + BC[1]*BC[1] );
19098  AB_MOD = sqrt(AB[0]*AB[0] + AB[1]*AB[1] );
19099  AC_MOD = sqrt(AC[0]*AC[0] + AC[1]*AC[1] );
19100  AB_CROSS_AC = AB[0]* AC[1] - AB[1]* AC[0];
19101 
19102  su2double Curvature_Trailing = fabs(1.0/(0.5*BC_MOD*AB_MOD*AC_MOD/AB_CROSS_AC));
19103 
19104  // su2double Curvature = 0.5*(Curvature_Leading + Curvature_Trailing);
19105 
19106  return Curvature_Trailing;
19107 
19108 }
19109 
19110 su2double CPhysicalGeometry::Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19111  unsigned long iVertex, Trailing_Point, Leading_Point;
19112  su2double MaxDistance, Distance, Twist = 0.0;
19113 
19114  /*--- Find the leading and trailing edges and compute the angle of attack ---*/
19115 
19116  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19117  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19118  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
19119  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
19120  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19121 
19122  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19123  }
19124 
19125  Twist = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER;
19126 
19127  return Twist;
19128 
19129 }
19130 
19131 void CPhysicalGeometry::Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal,
19132  vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19133 
19134  unsigned long iVertex, Trailing_Point, Leading_Point;
19135  su2double MaxDistance, Distance;
19136 
19137  /*--- Find the leading and trailing edges and compute the angle of attack ---*/
19138 
19139  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19140  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19141 
19142  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
19143  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
19144  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19145 
19146  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19147  }
19148 
19149  LeadingEdge[0] = Xcoord_Airfoil[Leading_Point];
19150  LeadingEdge[1] = Ycoord_Airfoil[Leading_Point];
19151  LeadingEdge[2] = Zcoord_Airfoil[Leading_Point];
19152 
19153  TrailingEdge[0] = Xcoord_Airfoil[Trailing_Point];
19154  TrailingEdge[1] = Ycoord_Airfoil[Trailing_Point];
19155  TrailingEdge[2] = Zcoord_Airfoil[Trailing_Point];
19156 
19157 }
19158 
19159 void CPhysicalGeometry::Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal,
19160  vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19161 
19162  unsigned long iVertex, Trailing_Point, Leading_Point;
19163  su2double MaxDistance, Distance;
19164 
19165  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19166  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19167  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0));
19168  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19169  }
19170 
19171  LeadingEdge[0] = Xcoord_Airfoil[Leading_Point];
19172  LeadingEdge[1] = Ycoord_Airfoil[Leading_Point];
19173  LeadingEdge[2] = Zcoord_Airfoil[Leading_Point];
19174 
19175  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19176  for (iVertex = 1; iVertex < Zcoord_Airfoil.size(); iVertex++) {
19177  Distance = sqrt(pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19178  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19179  }
19180 
19181  TrailingEdge[0] = 0.5*(Xcoord_Airfoil[Trailing_Point]+Xcoord_Airfoil[Leading_Point]);
19182  TrailingEdge[1] = 0.5*(Ycoord_Airfoil[Trailing_Point]+Ycoord_Airfoil[Leading_Point]);
19183  TrailingEdge[2] = 0.5*(Zcoord_Airfoil[Trailing_Point]+Zcoord_Airfoil[Leading_Point]);
19184 
19185 }
19186 
19187 su2double CPhysicalGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19188  unsigned long iVertex, Trailing_Point;
19189  su2double MaxDistance, Distance, Chord = 0.0;
19190 
19191  /*--- Find the leading and trailing edges and compute the angle of attack ---*/
19192  MaxDistance = 0.0; Trailing_Point = 0;
19193  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19194 
19195  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
19196  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
19197  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19198 
19199  if (MaxDistance < Distance) { MaxDistance = Distance; }
19200  }
19201 
19202  Chord = MaxDistance;
19203 
19204  return Chord;
19205 
19206 }
19207 
19208 su2double CPhysicalGeometry::Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19209 
19210  unsigned long iVertex, Trailing_Point;
19211  su2double MaxDistance, Distance, Width = 0.0;
19212 
19213  MaxDistance = 0.0; Trailing_Point = 0;
19214  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19215  Distance = fabs(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point]);
19216  if (MaxDistance < Distance) { MaxDistance = Distance; }
19217  }
19218 
19219  Width = MaxDistance;
19220  return Width;
19221 
19222 }
19223 
19224 su2double CPhysicalGeometry::Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19225 
19226  unsigned long iVertex, Trailing_Point;
19227  su2double MinDistance, Distance, WaterLineWidth = 0.0;
19228  su2double WaterLine = config->GetGeo_Waterline_Location();
19229 
19230  MinDistance = 1E10; WaterLineWidth = 0; Trailing_Point = 0;
19231  for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19232  Distance = fabs(Zcoord_Airfoil[iVertex] - WaterLine);
19233  if (Distance < MinDistance) {
19234  MinDistance = Distance;
19235  WaterLineWidth = fabs(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point]);
19236  }
19237  }
19238 
19239  return WaterLineWidth;
19240 
19241 }
19242 
19243 su2double CPhysicalGeometry::Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19244 
19245  unsigned long iVertex, Trailing_Point;
19246  su2double MaxDistance, Distance, Height = 0.0;
19247 
19248  MaxDistance = 0.0; Trailing_Point = 0;
19249  for (iVertex = 1; iVertex < Zcoord_Airfoil.size(); iVertex++) {
19250  Distance = sqrt(pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19251  if (MaxDistance < Distance) { MaxDistance = Distance; }
19252  }
19253 
19254  Height = MaxDistance;
19255 
19256  return Height;
19257 
19258 }
19259 
19260 su2double CPhysicalGeometry::Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19261 
19262  unsigned long iVertex, Trailing_Point, Leading_Point;
19263  su2double MaxDistance, Distance, LERadius = 0.0, X1, X2, X3, Y1, Y2, Y3, Ma, Mb, Xc, Yc, Radius;
19264 
19265  /*--- Find the leading and trailing edges and compute the radius of curvature ---*/
19266 
19267  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19268  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19269 
19270  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
19271  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
19272  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19273 
19274  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19275  }
19276 
19277  X1 = Xcoord_Airfoil[Leading_Point-3];
19278  Y1 = Zcoord_Airfoil[Leading_Point-3];
19279 
19280  X2 = Xcoord_Airfoil[Leading_Point];
19281  Y2 = Zcoord_Airfoil[Leading_Point];
19282 
19283  X3 = Xcoord_Airfoil[Leading_Point+3];
19284  Y3 = Zcoord_Airfoil[Leading_Point+3];
19285 
19286  if (X2 != X1) Ma = (Y2-Y1) / (X2-X1); else Ma = 0.0;
19287  if (X3 != X2) Mb = (Y3-Y2) / (X3-X2); else Mb = 0.0;
19288 
19289  if (Mb != Ma) Xc = (Ma*Mb*(Y1-Y3)+Mb*(X1+X2)-Ma*(X2+X3))/(2.0*(Mb-Ma)); else Xc = 0.0;
19290  if (Ma != 0.0) Yc = -(1.0/Ma)*(Xc-0.5*(X1+X2))+0.5*(Y1+Y2); else Yc = 0.0;
19291 
19292  Radius = sqrt((Xc-X1)*(Xc-X1)+(Yc-Y1)*(Yc-Y1));
19293  if (Radius != 0.0) LERadius = 1.0/Radius; else LERadius = 0.0;
19294 
19295  return LERadius;
19296 
19297 }
19298 
19299 su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil, su2double &ZLoc) {
19300 
19301  unsigned long iVertex, jVertex, n_Upper, n_Lower, Trailing_Point, Leading_Point;
19302  su2double Thickness_Location, Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Thickness_Value = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, zp1, zpn, Chord, MaxDistance, Distance, AoA;
19303  vector<su2double> Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Z2coord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_;
19304  su2double Zcoord_Up, Zcoord_Down, ZLoc_, YLoc_;
19305 
19306  /*--- Find the leading and trailing edges and compute the angle of attack ---*/
19307 
19308  MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0;
19309  for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19310  Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) +
19311  pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) +
19312  pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0));
19313 
19314  if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; }
19315  }
19316 
19317  AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER;
19318  Chord = MaxDistance;
19319 
19320  /*--- Translate to the origin ---*/
19321 
19322  Xcoord_Trailing = Xcoord_Airfoil[0];
19323  Ycoord_Trailing = Ycoord_Airfoil[0];
19324  Zcoord_Trailing = Zcoord_Airfoil[0];
19325 
19326  for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19327  Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing);
19328  Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing);
19329  Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing);
19330  }
19331 
19332  /*--- Rotate the airfoil ---*/
19333 
19334  ValCos = cos(AoA*PI_NUMBER/180.0);
19335  ValSin = sin(AoA*PI_NUMBER/180.0);
19336 
19337  for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) {
19338  XValue = Xcoord_Airfoil_[iVertex];
19339  ZValue = Zcoord_Airfoil_[iVertex];
19340 
19341  Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin;
19342  Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin;
19343  }
19344 
19345  /*--- Identify upper and lower side, and store the value of the normal --*/
19346 
19347  for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) {
19348  Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1];
19349  Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1];
19350  Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1];
19351  Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0));
19352  Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length;
19353 
19354  BiNormal[0] = Plane_Normal[0];
19355  BiNormal[1] = Plane_Normal[1];
19356  BiNormal[2] = Plane_Normal[2];
19357  Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0));
19358  BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length;
19359 
19360  Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1];
19361  Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2];
19362  Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0];
19363 
19364  Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]);
19365 
19366  unsigned short index = 2;
19367 
19368  if (Normal[index] >= 0.0) {
19369  Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]);
19370  Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]);
19371  Zcoord_Upper.push_back(Zcoord_Airfoil_[iVertex]);
19372  }
19373  else {
19374  Xcoord_Lower.push_back(Xcoord_Airfoil_[iVertex]);
19375  Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]);
19376  Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]);
19377  }
19378 
19379  }
19380 
19381  /*--- Order the arrays using the X component ---*/
19382 
19383  for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) {
19384  for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) {
19385  if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) {
19386  auxXCoord = Xcoord_Upper[jVertex]; Xcoord_Upper[jVertex] = Xcoord_Upper[jVertex+1]; Xcoord_Upper[jVertex+1] = auxXCoord;
19387  auxYCoord = Ycoord_Upper[jVertex]; Ycoord_Upper[jVertex] = Ycoord_Upper[jVertex+1]; Ycoord_Upper[jVertex+1] = auxYCoord;
19388  auxZCoord = Zcoord_Upper[jVertex]; Zcoord_Upper[jVertex] = Zcoord_Upper[jVertex+1]; Zcoord_Upper[jVertex+1] = auxZCoord;
19389  }
19390  }
19391  }
19392 
19393  /*--- Order the arrays using the X component ---*/
19394 
19395  for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) {
19396  for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) {
19397  if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) {
19398  auxXCoord = Xcoord_Lower[jVertex]; Xcoord_Lower[jVertex] = Xcoord_Lower[jVertex+1]; Xcoord_Lower[jVertex+1] = auxXCoord;
19399  auxYCoord = Ycoord_Lower[jVertex]; Ycoord_Lower[jVertex] = Ycoord_Lower[jVertex+1]; Ycoord_Lower[jVertex+1] = auxYCoord;
19400  auxZCoord = Zcoord_Lower[jVertex]; Zcoord_Lower[jVertex] = Zcoord_Lower[jVertex+1]; Zcoord_Lower[jVertex+1] = auxZCoord;
19401  }
19402  }
19403  }
19404 
19405  n_Upper = Xcoord_Upper.size();
19406  if (n_Upper > 1) {
19407  zp1 = (Zcoord_Upper[1]-Zcoord_Upper[0])/(Xcoord_Upper[1]-Xcoord_Upper[0]);
19408  zpn = (Zcoord_Upper[n_Upper-1]-Zcoord_Upper[n_Upper-2])/(Xcoord_Upper[n_Upper-1]-Xcoord_Upper[n_Upper-2]);
19409  Z2coord_Upper.resize(n_Upper+1);
19410  SetSpline(Xcoord_Upper, Zcoord_Upper, n_Upper, zp1, zpn, Z2coord_Upper);
19411  }
19412 
19413  n_Lower = Xcoord_Lower.size();
19414  if (n_Lower > 1) {
19415  zp1 = (Zcoord_Lower[1]-Zcoord_Lower[0])/(Xcoord_Lower[1]-Xcoord_Lower[0]);
19416  zpn = (Zcoord_Lower[n_Lower-1]-Zcoord_Lower[n_Lower-2])/(Xcoord_Lower[n_Lower-1]-Xcoord_Lower[n_Lower-2]);
19417  Z2coord_Lower.resize(n_Lower+1);
19418  SetSpline(Xcoord_Lower, Zcoord_Lower, n_Lower, zp1, zpn, Z2coord_Lower);
19419  }
19420 
19421  if ((n_Upper > 1) && (n_Lower > 1)) {
19422 
19423  Thickness_Location = - Chord*(1.0-Location);
19424 
19425  Zcoord_Up = GetSpline(Xcoord_Upper, Zcoord_Upper, Z2coord_Upper, n_Upper, Thickness_Location);
19426  Zcoord_Down = GetSpline(Xcoord_Lower, Zcoord_Lower, Z2coord_Lower, n_Lower, Thickness_Location);
19427 
19428  YLoc_ = Thickness_Location;
19429  ZLoc_ = 0.5*(Zcoord_Up + Zcoord_Down);
19430 
19431  ZLoc = sin(-AoA*PI_NUMBER/180.0)*YLoc_ + cos(-AoA*PI_NUMBER/180.0)*ZLoc_ + Zcoord_Trailing;
19432 
19433  /*--- Compute the thickness (we add a fabs because we can not guarantee the
19434  right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/
19435 
19436  Thickness_Value = fabs(Zcoord_Up - Zcoord_Down);
19437 
19438  }
19439  else { Thickness_Value = 0.0; }
19440 
19441  return Thickness_Value;
19442 
19443 }
19444 
19446  vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19447  unsigned long iVertex;
19448  su2double Area_Value = 0.0;
19449  vector<su2double> Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_;
19450  su2double DeltaZ, DeltaX, X, Z;
19451 
19452  /*--- Use the Green theorem to evaluate the area (the points have been sortered),
19453  we assume that the airfoil is in the X-Z plane ---*/
19454 
19455  Area_Value = 0.0;
19456 
19457  for (iVertex = 0; iVertex < Xcoord_Airfoil.size()-1; iVertex++) {
19458  X = 0.5*(Xcoord_Airfoil[iVertex]+Xcoord_Airfoil[iVertex+1]);
19459  Z = 0.5*(Zcoord_Airfoil[iVertex]+Zcoord_Airfoil[iVertex+1]);
19460  DeltaX = Xcoord_Airfoil[iVertex+1] - Xcoord_Airfoil[iVertex];
19461  DeltaZ = Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex];
19462  Area_Value += 0.5*( X*DeltaZ-Z*DeltaX);
19463  }
19464 
19465  X = 0.5*(Xcoord_Airfoil[Xcoord_Airfoil.size()-1]+Xcoord_Airfoil[0]);
19466  Z = 0.5*(Zcoord_Airfoil[Xcoord_Airfoil.size()-1]+Zcoord_Airfoil[0]);
19467  DeltaX = Xcoord_Airfoil[0] - Xcoord_Airfoil[Xcoord_Airfoil.size()-1];
19468  DeltaZ = Zcoord_Airfoil[0] - Zcoord_Airfoil[Xcoord_Airfoil.size()-1];
19469  Area_Value += 0.5 * (X*DeltaZ-Z*DeltaX);
19470 
19471  Area_Value = fabs(Area_Value);
19472 
19473  return Area_Value;
19474 
19475 }
19476 
19478  vector<su2double> &Xcoord_Airfoil, vector<su2double> &Ycoord_Airfoil, vector<su2double> &Zcoord_Airfoil) {
19479  unsigned long iVertex;
19480  su2double Length_Value = 0.0, Length_Value_ = 0.0;
19481  su2double DeltaZ, DeltaX;
19482 
19483  /*--- Not that in a symmetry plane configuration there is an extra edge that connects
19484  the two extremes, and we really don't now the curve orientation. We will evaluate
19485  both distance and picked the smallest one ---*/
19486 
19487  Length_Value = 0.0;
19488  for (iVertex = 0; iVertex < Xcoord_Airfoil.size()-2; iVertex++) {
19489  DeltaX = Xcoord_Airfoil[iVertex+1] - Xcoord_Airfoil[iVertex];
19490  DeltaZ = Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex];
19491  Length_Value += sqrt(DeltaX*DeltaX + DeltaZ*DeltaZ);
19492  }
19493 
19494  Length_Value_ = 0.0;
19495  for (iVertex = 1; iVertex < Xcoord_Airfoil.size()-1; iVertex++) {
19496  DeltaX = Xcoord_Airfoil[iVertex+1] - Xcoord_Airfoil[iVertex];
19497  DeltaZ = Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex];
19498  Length_Value_ += sqrt(DeltaX*DeltaX + DeltaZ*DeltaZ);
19499  }
19500 
19501  Length_Value = min(Length_Value, Length_Value_);
19502 
19503  return Length_Value;
19504 
19505 }
19506 
19507 void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface,
19508  su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, su2double &Wing_MinChord, su2double &Wing_MaxChord,
19509  su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius,
19510  su2double &Wing_MinToC, su2double &Wing_MaxToC, su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, su2double &Wing_MaxCurvature,
19511  su2double &Wing_MaxDihedral) {
19512 
19513  unsigned short iPlane, iDim, nPlane = 0;
19514  unsigned long iVertex;
19515  su2double MinPlane, MaxPlane, dPlane, *Area, *MaxThickness, *ToC, *Chord, *LERadius, *Twist, *Curvature, *Dihedral, SemiSpan;
19516  vector<su2double> *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil;
19517  ofstream Wing_File, Section_File;
19518 
19519  /*--- Make a large number of section cuts for approximating volume ---*/
19520 
19521  nPlane = config->GetnWingStations();
19522  SemiSpan = config->GetSemiSpan();
19523 
19524  /*--- Allocate memory for the section cutting ---*/
19525 
19526  Area = new su2double [nPlane];
19527  MaxThickness = new su2double [nPlane];
19528  Chord = new su2double [nPlane];
19529  LERadius = new su2double [nPlane];
19530  ToC = new su2double [nPlane];
19531  Twist = new su2double [nPlane];
19532  Curvature = new su2double [nPlane];
19533  Dihedral = new su2double [nPlane];
19534 
19535  su2double **LeadingEdge = new su2double*[nPlane];
19536  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19537  LeadingEdge[iPlane] = new su2double[nDim];
19538 
19539  su2double **TrailingEdge = new su2double*[nPlane];
19540  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19541  TrailingEdge[iPlane] = new su2double[nDim];
19542 
19543  su2double **Plane_P0 = new su2double*[nPlane];
19544  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19545  Plane_P0[iPlane] = new su2double[nDim];
19546 
19547  su2double **Plane_Normal = new su2double*[nPlane];
19548  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19549  Plane_Normal[iPlane] = new su2double[nDim];
19550 
19551  MinPlane = config->GetStations_Bounds(0); MaxPlane = config->GetStations_Bounds(1);
19552  dPlane = fabs((MaxPlane - MinPlane)/su2double(nPlane-1));
19553 
19554  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19555  Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0;
19556  Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0;
19557  Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0;
19558 
19559  if (config->GetGeo_Description() == WING) {
19560  Plane_Normal[iPlane][1] = 1.0;
19561  Plane_P0[iPlane][1] = MinPlane + iPlane*dPlane;
19562  }
19563 
19564  if (config->GetGeo_Description() == TWOD_AIRFOIL) {
19565  Plane_Normal[iPlane][2] = 1.0;
19566  Plane_P0[iPlane][2] = MinPlane + iPlane*dPlane;
19567  }
19568 
19569  }
19570 
19571  /*--- Allocate some vectors for storing airfoil coordinates ---*/
19572 
19573  Xcoord_Airfoil = new vector<su2double>[nPlane];
19574  Ycoord_Airfoil = new vector<su2double>[nPlane];
19575  Zcoord_Airfoil = new vector<su2double>[nPlane];
19576  Variable_Airfoil = new vector<su2double>[nPlane];
19577 
19578  /*--- Create the section slices through the geometry ---*/
19579 
19580  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19581 
19582  ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane],
19583  -1E6, 1E6, -1E6, 1E6, -1E6, 1E6, NULL, Xcoord_Airfoil[iPlane],
19584  Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane],
19585  Variable_Airfoil[iPlane], original_surface, config);
19586 
19587  }
19588 
19589  /*--- Compute airfoil characteristic only in the master node ---*/
19590 
19591  if (rank == MASTER_NODE) {
19592 
19593  /*--- Write an output file---*/
19594 
19595  if (config->GetOutput_FileFormat() == PARAVIEW) {
19596  Wing_File.open("wing_description.csv", ios::out);
19597  if (config->GetSystemMeasurements() == US)
19598  Wing_File << "\"yCoord/SemiSpan\",\"Area (in^2)\",\"Max. Thickness (in)\",\"Chord (in)\",\"Leading Edge Radius (1/in)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Curvature (1/in)\",\"Dihedral (deg)\",\"Leading Edge XLoc/SemiSpan\",\"Leading Edge ZLoc/SemiSpan\",\"Trailing Edge XLoc/SemiSpan\",\"Trailing Edge ZLoc/SemiSpan\"" << endl;
19599  else
19600  Wing_File << "\"yCoord/SemiSpan\",\"Area (m^2)\",\"Max. Thickness (m)\",\"Chord (m)\",\"Leading Edge Radius (1/m)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Curvature (1/in)\",\"Dihedral (deg)\",\"Leading Edge XLoc/SemiSpan\",\"Leading Edge ZLoc/SemiSpan\",\"Trailing Edge XLoc/SemiSpan\",\"Trailing Edge ZLoc/SemiSpan\"" << endl;
19601  }
19602  else {
19603  Wing_File.open("wing_description.dat", ios::out);
19604  Wing_File << "TITLE = \"Wing description\"" << endl;
19605  if (config->GetSystemMeasurements() == US)
19606  Wing_File << "VARIABLES = \"<greek>h</greek>\",\"Area (in<sup>2</sup>)\",\"Max. Thickness (in)\",\"Chord (in)\",\"Leading Edge Radius (1/in)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Curvature (1/in)\",\"Dihedral (deg)\",\"Leading Edge XLoc/SemiSpan\",\"Leading Edge ZLoc/SemiSpan\",\"Trailing Edge XLoc/SemiSpan\",\"Trailing Edge ZLoc/SemiSpan\"" << endl;
19607  else
19608  Wing_File << "VARIABLES = \"<greek>h</greek>\",\"Area (m<sup>2</sup>)\",\"Max. Thickness (m)\",\"Chord (m)\",\"Leading Edge Radius (1/m)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Curvature (1/m)\",\"Dihedral (deg)\",\"Leading Edge XLoc/SemiSpan\",\"Leading Edge ZLoc/SemiSpan\",\"Trailing Edge XLoc/SemiSpan\",\"Trailing Edge ZLoc/SemiSpan\"" << endl;
19609  Wing_File << "ZONE T= \"Baseline wing\"" << endl;
19610  }
19611 
19612 
19613  /*--- Evaluate geometrical quatities that do not require any kind of filter, local to each point ---*/
19614 
19615  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19616 
19617  for (iDim = 0; iDim < nDim; iDim++) {
19618  LeadingEdge[iPlane][iDim] = 0.0;
19619  TrailingEdge[iPlane][iDim] = 0.0;
19620  }
19621 
19622  Area[iPlane] = 0.0;
19623  MaxThickness[iPlane] = 0.0;
19624  Chord[iPlane] = 0.0;
19625  LERadius[iPlane] = 0.0;
19626  ToC[iPlane] = 0.0;
19627  Twist[iPlane] = 0.0;
19628 
19629  if (Xcoord_Airfoil[iPlane].size() > 1) {
19630 
19631  Compute_Wing_LeadingTrailing(LeadingEdge[iPlane], TrailingEdge[iPlane], Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19632 
19633  Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19634 
19635  MaxThickness[iPlane] = Compute_MaxThickness(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19636 
19637  Chord[iPlane] = Compute_Chord(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19638 
19639  Twist[iPlane] = Compute_Twist(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19640 
19641  LERadius[iPlane] = Compute_LERadius(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19642 
19643  ToC[iPlane] = MaxThickness[iPlane] / Chord[iPlane];
19644 
19645 
19646  }
19647 
19648  }
19649 
19650  /*--- Evaluate geometrical quatities that have been computed using a filtered value (they depend on more than one point) ---*/
19651 
19652  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19653 
19654  Curvature[iPlane] = 0.0;
19655  Dihedral[iPlane] = 0.0;
19656 
19657  if (Xcoord_Airfoil[iPlane].size() > 1) {
19658 
19659  if ((iPlane == 0) || (iPlane == nPlane-1)) Curvature[iPlane] = 0.0;
19660  else Curvature[iPlane] = Compute_Curvature(LeadingEdge[iPlane-1], TrailingEdge[iPlane-1],
19661  LeadingEdge[iPlane], TrailingEdge[iPlane],
19662  LeadingEdge[iPlane+1], TrailingEdge[iPlane+1]);
19663 
19664  if (iPlane == 0) Dihedral[iPlane] = 0.0;
19665  else Dihedral[iPlane] = Compute_Dihedral(LeadingEdge[iPlane-1], TrailingEdge[iPlane-1],
19666  LeadingEdge[iPlane], TrailingEdge[iPlane]);
19667 
19668  }
19669 
19670  }
19671 
19672  /*--- Set the curvature and dihedral angles at the extremes ---*/
19673 
19674  if (nPlane > 1) {
19675  if ((Xcoord_Airfoil[0].size() != 0) && (Xcoord_Airfoil[1].size() != 0)) {
19676  Curvature[0] = Curvature[1]; Dihedral[0] = Dihedral[1];
19677  }
19678  if ((Xcoord_Airfoil[nPlane-1].size() != 0) && (Xcoord_Airfoil[nPlane-2].size() != 0)) {
19679  Curvature[nPlane-1] = Curvature[nPlane-2];
19680  }
19681  }
19682 
19683  /*--- Plot the geometrical quatities ---*/
19684 
19685  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19686  if (Xcoord_Airfoil[iPlane].size() > 1) {
19687  if (config->GetOutput_FileFormat() == PARAVIEW) {
19688  Wing_File << Ycoord_Airfoil[iPlane][0]/SemiSpan <<", "<< Area[iPlane] <<", "<< MaxThickness[iPlane] <<", "<< Chord[iPlane] <<", "<< LERadius[iPlane] <<", "<< ToC[iPlane]
19689  <<", "<< Twist[iPlane] <<", "<< Curvature[iPlane] <<", "<< Dihedral[iPlane]
19690  <<", "<< LeadingEdge[iPlane][0]/SemiSpan <<", "<< LeadingEdge[iPlane][2]/SemiSpan
19691  <<", "<< TrailingEdge[iPlane][0]/SemiSpan <<", "<< TrailingEdge[iPlane][2]/SemiSpan << endl;
19692  }
19693  else {
19694  Wing_File << Ycoord_Airfoil[iPlane][0]/SemiSpan <<" "<< Area[iPlane] <<" "<< MaxThickness[iPlane] <<" "<< Chord[iPlane] <<" "<< LERadius[iPlane] <<" "<< ToC[iPlane]
19695  <<" "<< Twist[iPlane] <<" "<< Curvature[iPlane] <<" "<< Dihedral[iPlane]
19696  <<" "<< LeadingEdge[iPlane][0]/SemiSpan <<" "<< LeadingEdge[iPlane][2]/SemiSpan
19697  <<" "<< TrailingEdge[iPlane][0]/SemiSpan <<" "<< TrailingEdge[iPlane][2]/SemiSpan << endl;
19698 
19699  }
19700  }
19701  }
19702 
19703  Wing_File.close();
19704 
19705  Section_File.open("wing_slices.dat", ios::out);
19706 
19707  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19708 
19709  if (iPlane == 0) {
19710  Section_File << "TITLE = \"Aircraft Slices\"" << endl;
19711  if (config->GetSystemMeasurements() == US)
19712  Section_File << "VARIABLES = \"x (in)\", \"y (in)\", \"z (in)\", \"x<sub>2D</sub>/c\", \"y<sub>2D</sub>/c\"" << endl;
19713  else Section_File << "VARIABLES = \"x (m)\", \"y (m)\", \"z (m)\", \"x<sub>2D</sub>/c\", \"y<sub>2D</sub>/c\"" << endl;
19714  }
19715 
19716  if (Xcoord_Airfoil[iPlane].size() > 1) {
19717 
19718  Section_File << "ZONE T=\"<greek>h</greek> = " << Ycoord_Airfoil[iPlane][0]/SemiSpan << " \", I= " << Xcoord_Airfoil[iPlane].size() << ", F=POINT" << endl;
19719 
19720  for (iVertex = 0; iVertex < Xcoord_Airfoil[iPlane].size(); iVertex++) {
19721 
19722  /*--- Move to the origin ---*/
19723 
19724  su2double XValue_ = Xcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][0];
19725  su2double ZValue_ = Zcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][2];
19726 
19727  /*--- Rotate the airfoil and divide by the chord ---*/
19728 
19729  su2double ValCos = cos(Twist[iPlane]*PI_NUMBER/180.0);
19730  su2double ValSin = sin(Twist[iPlane]*PI_NUMBER/180.0);
19731 
19732  su2double XValue = (XValue_*ValCos - ZValue_*ValSin) / Chord[iPlane];
19733  su2double ZValue = (ZValue_*ValCos + XValue_*ValSin) / Chord[iPlane];
19734 
19735  /*--- Write the file ---*/
19736 
19737  Section_File << Xcoord_Airfoil[iPlane][iVertex] << " " << Ycoord_Airfoil[iPlane][iVertex] << " " << Zcoord_Airfoil[iPlane][iVertex] << " " << XValue << " " << ZValue << endl;
19738  }
19739  }
19740 
19741  }
19742 
19743  Section_File.close();
19744 
19745 
19746  /*--- Compute the wing volume using a composite Simpson's rule ---*/
19747 
19748  Wing_Volume = 0.0;
19749  for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) {
19750  if (Xcoord_Airfoil[iPlane].size() > 1) {
19751  Wing_Volume += (1.0/3.0)*dPlane*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]);
19752  }
19753  }
19754 
19755  /*--- Evaluate Max and Min quantities ---*/
19756 
19757  Wing_MaxMaxThickness = -1E6; Wing_MinMaxThickness = 1E6; Wing_MinChord = 1E6; Wing_MaxChord = -1E6;
19758  Wing_MinLERadius = 1E6; Wing_MaxLERadius = -1E6; Wing_MinToC = 1E6; Wing_MaxToC = -1E6;
19759  Wing_MaxTwist = -1E6; Wing_MaxCurvature = -1E6; Wing_MaxDihedral = -1E6;
19760 
19761  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19762  if (MaxThickness[iPlane] != 0.0) Wing_MinMaxThickness = min(Wing_MinMaxThickness, MaxThickness[iPlane]);
19763  Wing_MaxMaxThickness = max(Wing_MaxMaxThickness, MaxThickness[iPlane]);
19764  if (Chord[iPlane] != 0.0) Wing_MinChord = min(Wing_MinChord, Chord[iPlane]);
19765  Wing_MaxChord = max(Wing_MaxChord, Chord[iPlane]);
19766  if (LERadius[iPlane] != 0.0) Wing_MinLERadius = min(Wing_MinLERadius, LERadius[iPlane]);
19767  Wing_MaxLERadius = max(Wing_MaxLERadius, LERadius[iPlane]);
19768  if (ToC[iPlane] != 0.0) Wing_MinToC = min(Wing_MinToC, ToC[iPlane]);
19769  Wing_MaxToC = max(Wing_MaxToC, ToC[iPlane]);
19770  Wing_ObjFun_MinToC = sqrt((Wing_MinToC - 0.07)*(Wing_MinToC - 0.07));
19771  Wing_MaxTwist = max(Wing_MaxTwist, fabs(Twist[iPlane]));
19772  Wing_MaxCurvature = max(Wing_MaxCurvature, Curvature[iPlane]);
19773  Wing_MaxDihedral = max(Wing_MaxDihedral, fabs(Dihedral[iPlane]));
19774  }
19775 
19776  }
19777 
19778  /*--- Free memory for the section cuts ---*/
19779 
19780  delete [] Xcoord_Airfoil;
19781  delete [] Ycoord_Airfoil;
19782  delete [] Zcoord_Airfoil;
19783  delete [] Variable_Airfoil;
19784 
19785  for (iPlane = 0; iPlane < nPlane; iPlane++)
19786  delete [] LeadingEdge[iPlane];
19787  delete [] LeadingEdge;
19788 
19789  for (iPlane = 0; iPlane < nPlane; iPlane++)
19790  delete [] TrailingEdge[iPlane];
19791  delete [] TrailingEdge;
19792 
19793  for (iPlane = 0; iPlane < nPlane; iPlane++)
19794  delete [] Plane_P0[iPlane];
19795  delete [] Plane_P0;
19796 
19797  for (iPlane = 0; iPlane < nPlane; iPlane++)
19798  delete [] Plane_Normal[iPlane];
19799  delete [] Plane_Normal;
19800 
19801  delete [] Area;
19802  delete [] MaxThickness;
19803  delete [] Chord;
19804  delete [] LERadius;
19805  delete [] ToC;
19806  delete [] Twist;
19807  delete [] Curvature;
19808  delete [] Dihedral;
19809 
19810 }
19811 
19812 void CPhysicalGeometry::Compute_Fuselage(CConfig *config, bool original_surface,
19813  su2double &Fuselage_Volume, su2double &Fuselage_WettedArea,
19814  su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth,
19815  su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth,
19816  su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight,
19817  su2double &Fuselage_MaxCurvature) {
19818 
19819  unsigned short iPlane, iDim, nPlane = 0;
19820  unsigned long iVertex;
19821  su2double MinPlane, MaxPlane, dPlane, *Area, *Length, *Width, *WaterLineWidth, *Height, *Curvature;
19822  vector<su2double> *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil;
19823  ofstream Fuselage_File, Section_File;
19824 
19825  /*--- Make a large number of section cuts for approximating volume ---*/
19826 
19827  nPlane = config->GetnWingStations();
19828 
19829  /*--- Allocate memory for the section cutting ---*/
19830 
19831  Area = new su2double [nPlane];
19832  Length = new su2double [nPlane];
19833  Width = new su2double [nPlane];
19834  WaterLineWidth = new su2double [nPlane];
19835  Height = new su2double [nPlane];
19836  Curvature = new su2double [nPlane];
19837 
19838  su2double **LeadingEdge = new su2double*[nPlane];
19839  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19840  LeadingEdge[iPlane] = new su2double[nDim];
19841 
19842  su2double **TrailingEdge = new su2double*[nPlane];
19843  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19844  TrailingEdge[iPlane] = new su2double[nDim];
19845 
19846  su2double **Plane_P0 = new su2double*[nPlane];
19847  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19848  Plane_P0[iPlane] = new su2double[nDim];
19849 
19850  su2double **Plane_Normal = new su2double*[nPlane];
19851  for (iPlane = 0; iPlane < nPlane; iPlane++ )
19852  Plane_Normal[iPlane] = new su2double[nDim];
19853 
19854  MinPlane = config->GetStations_Bounds(0); MaxPlane = config->GetStations_Bounds(1);
19855  dPlane = fabs((MaxPlane - MinPlane)/su2double(nPlane-1));
19856 
19857  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19858  Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0;
19859  Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0;
19860  Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0;
19861 
19862  Plane_Normal[iPlane][0] = 1.0;
19863  Plane_P0[iPlane][0] = MinPlane + iPlane*dPlane;
19864 
19865  }
19866 
19867  /*--- Allocate some vectors for storing airfoil coordinates ---*/
19868 
19869  Xcoord_Airfoil = new vector<su2double>[nPlane];
19870  Ycoord_Airfoil = new vector<su2double>[nPlane];
19871  Zcoord_Airfoil = new vector<su2double>[nPlane];
19872  Variable_Airfoil = new vector<su2double>[nPlane];
19873 
19874  /*--- Create the section slices through the geometry ---*/
19875 
19876  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19877 
19878  ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane],
19879  -1E6, 1E6, -1E6, 1E6, -1E6, 1E6, NULL, Xcoord_Airfoil[iPlane],
19880  Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane],
19881  Variable_Airfoil[iPlane], original_surface, config);
19882  }
19883 
19884  /*--- Compute the area at each section ---*/
19885 
19886  if (rank == MASTER_NODE) {
19887 
19888  /*--- Write an output file---*/
19889 
19890  if (config->GetOutput_FileFormat() == PARAVIEW) {
19891  Fuselage_File.open("fuselage_description.csv", ios::out);
19892  if (config->GetSystemMeasurements() == US)
19893  Fuselage_File << "\"x (in)\",\"Area (in^2)\",\"Length (in)\",\"Width (in)\",\"Waterline width (in)\",\"Height (in)\",\"Curvature (1/in)\",\"Generatrix Curve X (in)\",\"Generatrix Curve Y (in)\",\"Generatrix Curve Z (in)\",\"Axis Curve X (in)\",\"Axis Curve Y (in)\",\"Axis Curve Z (in)\"" << endl;
19894  else
19895  Fuselage_File << "\"x (m)\",\"Area (m^2)\",\"Length (m)\",\"Width (m)\",\"Waterline width (m)\",\"Height (m)\",\"Curvature (1/in)\",\"Generatrix Curve X (m)\",\"Generatrix Curve Y (m)\",\"Generatrix Curve Z (m)\",\"Axis Curve X (m)\",\"Axis Curve Y (m)\",\"Axis Curve Z (m)\"" << endl;
19896  }
19897  else {
19898  Fuselage_File.open("fuselage_description.dat", ios::out);
19899  Fuselage_File << "TITLE = \"Fuselage description\"" << endl;
19900  if (config->GetSystemMeasurements() == US)
19901  Fuselage_File << "VARIABLES = \"x (in)\",\"Area (in<sup>2</sup>)\",\"Length (in)\",\"Width (in)\",\"Waterline width (in)\",\"Height (in)\",\"Curvature (1/in)\",\"Generatrix Curve X (in)\",\"Generatrix Curve Y (in)\",\"Generatrix Curve Z (in)\",\"Axis Curve X (in)\",\"Axis Curve Y (in)\",\"Axis Curve Z (in)\"" << endl;
19902  else
19903  Fuselage_File << "VARIABLES = \"x (m)\",\"Area (m<sup>2</sup>)\",\"Length (m)\",\"Width (m)\",\"Waterline width (m)\",\"Height (m)\",\"Curvature (1/m)\",\"Generatrix Curve X (m)\",\"Generatrix Curve Y (m)\",\"Generatrix Curve Z (m)\",\"Axis Curve X (m)\",\"Axis Curve Y (m)\",\"Axis Curve Z (m)\"" << endl;
19904  Fuselage_File << "ZONE T= \"Baseline fuselage\"" << endl;
19905  }
19906 
19907 
19908  /*--- Evaluate geometrical quatities that do not require any kind of filter, local to each point ---*/
19909 
19910  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19911 
19912  for (iDim = 0; iDim < nDim; iDim++) {
19913  LeadingEdge[iPlane][iDim] = 0.0;
19914  TrailingEdge[iPlane][iDim] = 0.0;
19915  }
19916 
19917  Area[iPlane] = 0.0;
19918  Length[iPlane] = 0.0;
19919  Width[iPlane] = 0.0;
19920  WaterLineWidth[iPlane] = 0.0;
19921  Height[iPlane] = 0.0;
19922 
19923  if (Xcoord_Airfoil[iPlane].size() > 1) {
19924 
19925  Compute_Fuselage_LeadingTrailing(LeadingEdge[iPlane], TrailingEdge[iPlane], Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19926 
19927  Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19928 
19929  Length[iPlane] = Compute_Length(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19930 
19931  Width[iPlane] = Compute_Width(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19932 
19933  WaterLineWidth[iPlane] = Compute_WaterLineWidth(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19934 
19935  Height[iPlane] = Compute_Height(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
19936 
19937  }
19938 
19939  }
19940 
19941  /*--- Evaluate geometrical quatities that have been computed using a filtered value (they depend on more than one point) ---*/
19942 
19943  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19944 
19945  Curvature[iPlane] = 0.0;
19946 
19947  if (Xcoord_Airfoil[iPlane].size() > 1) {
19948 
19949  if ((iPlane == 0) || (iPlane == nPlane-1)) Curvature[iPlane] = 0.0;
19950  else Curvature[iPlane] = Compute_Curvature(LeadingEdge[iPlane-1], TrailingEdge[iPlane-1],
19951  LeadingEdge[iPlane], TrailingEdge[iPlane],
19952  LeadingEdge[iPlane+1], TrailingEdge[iPlane+1]);
19953 
19954  }
19955 
19956  }
19957 
19958  /*--- Set the curvature and dihedral angles at the extremes ---*/
19959 
19960  if (nPlane > 1) {
19961  if ((Xcoord_Airfoil[0].size() != 0) && (Xcoord_Airfoil[1].size() != 0)) {
19962  Curvature[0] = Curvature[1];
19963  }
19964  if ((Xcoord_Airfoil[nPlane-1].size() != 0) && (Xcoord_Airfoil[nPlane-2].size() != 0)) {
19965  Curvature[nPlane-1] = Curvature[nPlane-2];
19966  }
19967  }
19968 
19969  /*--- Plot the geometrical quatities ---*/
19970 
19971  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19972  if (Xcoord_Airfoil[iPlane].size() > 1) {
19973  if (config->GetOutput_FileFormat() == PARAVIEW) {
19974  Fuselage_File << -Ycoord_Airfoil[iPlane][0] <<", "<< Area[iPlane] <<", "<< Length[iPlane] <<", "<< Width[iPlane] <<", "<< WaterLineWidth[iPlane] <<", "<< Height[iPlane] <<", "<< Curvature[iPlane]
19975  <<", "<< -LeadingEdge[iPlane][1] <<", "<< LeadingEdge[iPlane][0] <<", "<< LeadingEdge[iPlane][2]
19976  <<", "<< -TrailingEdge[iPlane][1] <<", "<< TrailingEdge[iPlane][0] <<", "<< TrailingEdge[iPlane][2] << endl;
19977  }
19978  else {
19979  Fuselage_File << -Ycoord_Airfoil[iPlane][0] <<" "<< Area[iPlane] <<" "<< Length[iPlane] <<" "<< Width[iPlane] <<" "<< WaterLineWidth[iPlane] <<" "<< Height[iPlane] <<" "<< Curvature[iPlane]
19980  <<" "<< -LeadingEdge[iPlane][1] <<" "<< LeadingEdge[iPlane][0] <<" "<< LeadingEdge[iPlane][2]
19981  <<" "<< -TrailingEdge[iPlane][1] <<" "<< TrailingEdge[iPlane][0] <<" "<< TrailingEdge[iPlane][2] << endl;
19982  }
19983  }
19984  }
19985 
19986  Fuselage_File.close();
19987 
19988  Section_File.open("fuselage_slices.dat", ios::out);
19989 
19990  for (iPlane = 0; iPlane < nPlane; iPlane++) {
19991 
19992  if (iPlane == 0) {
19993  Section_File << "TITLE = \"Aircraft Slices\"" << endl;
19994  if (config->GetSystemMeasurements() == US)
19995  Section_File << "VARIABLES = \"x (in)\", \"y (in)\", \"z (in)\"" << endl;
19996  else Section_File << "VARIABLES = \"x (m)\", \"y (m)\", \"z (m)\"" << endl;
19997  }
19998 
19999  if (Xcoord_Airfoil[iPlane].size() > 1) {
20000 
20001  Section_File << "ZONE T=\"X = " << -Ycoord_Airfoil[iPlane][0] << " \", I= " << Ycoord_Airfoil[iPlane].size() << ", F=POINT" << endl;
20002 
20003  for (iVertex = 0; iVertex < Xcoord_Airfoil[iPlane].size(); iVertex++) {
20004 
20005  /*--- Write the file ---*/
20006 
20007  Section_File << -Ycoord_Airfoil[iPlane][iVertex] << " " << Xcoord_Airfoil[iPlane][iVertex] << " " << Zcoord_Airfoil[iPlane][iVertex] << endl;
20008  }
20009  }
20010 
20011  }
20012 
20013  Section_File.close();
20014 
20015 
20016  /*--- Compute the fuselage volume using a composite Simpson's rule ---*/
20017 
20018  Fuselage_Volume = 0.0;
20019  for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) {
20020  if (Xcoord_Airfoil[iPlane].size() > 1) {
20021  Fuselage_Volume += (1.0/3.0)*dPlane*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]);
20022  }
20023  }
20024 
20025  /*--- Compute the fuselage wetted area ---*/
20026 
20027  Fuselage_WettedArea = 0.0;
20028  if (Xcoord_Airfoil[0].size() > 1) Fuselage_WettedArea += (1.0/2.0)*dPlane*Length[0];
20029  for (iPlane = 1; iPlane < nPlane-1; iPlane++) {
20030  if (Xcoord_Airfoil[iPlane].size() > 1) {
20031  Fuselage_WettedArea += dPlane*Length[iPlane];
20032  }
20033  }
20034  if (Xcoord_Airfoil[nPlane-1].size() > 1) Fuselage_WettedArea += (1.0/2.0)*dPlane*Length[nPlane-1];
20035 
20036  /*--- Evaluate Max and Min quantities ---*/
20037 
20038  Fuselage_MaxWidth = -1E6; Fuselage_MinWidth = 1E6;
20039  Fuselage_MaxWaterLineWidth = -1E6; Fuselage_MinWaterLineWidth = 1E6;
20040  Fuselage_MaxHeight = -1E6; Fuselage_MinHeight = 1E6;
20041  Fuselage_MaxCurvature = -1E6;
20042 
20043  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20044  if (Width[iPlane] != 0.0) Fuselage_MinWidth = min(Fuselage_MinWidth, Width[iPlane]);
20045  Fuselage_MaxWidth = max(Fuselage_MaxWidth, Width[iPlane]);
20046  if (WaterLineWidth[iPlane] != 0.0) Fuselage_MinWaterLineWidth = min(Fuselage_MinWaterLineWidth, WaterLineWidth[iPlane]);
20047  Fuselage_MaxWaterLineWidth = max(Fuselage_MaxWaterLineWidth, WaterLineWidth[iPlane]);
20048  if (Height[iPlane] != 0.0) Fuselage_MinHeight = min(Fuselage_MinHeight, Height[iPlane]);
20049  Fuselage_MaxHeight = max(Fuselage_MaxHeight, Height[iPlane]);
20050  Fuselage_MaxCurvature = max(Fuselage_MaxCurvature, Curvature[iPlane]);
20051  }
20052 
20053  }
20054 
20055  /*--- Free memory for the section cuts ---*/
20056 
20057  delete [] Xcoord_Airfoil;
20058  delete [] Ycoord_Airfoil;
20059  delete [] Zcoord_Airfoil;
20060  delete [] Variable_Airfoil;
20061 
20062  for (iPlane = 0; iPlane < nPlane; iPlane++)
20063  delete [] LeadingEdge[iPlane];
20064  delete [] LeadingEdge;
20065 
20066  for (iPlane = 0; iPlane < nPlane; iPlane++)
20067  delete [] TrailingEdge[iPlane];
20068  delete [] TrailingEdge;
20069 
20070  for (iPlane = 0; iPlane < nPlane; iPlane++)
20071  delete [] Plane_P0[iPlane];
20072  delete [] Plane_P0;
20073 
20074  for (iPlane = 0; iPlane < nPlane; iPlane++)
20075  delete [] Plane_Normal[iPlane];
20076  delete [] Plane_Normal;
20077 
20078  delete [] Area;
20079  delete [] Length;
20080  delete [] Width;
20081  delete [] WaterLineWidth;
20082  delete [] Height;
20083  delete [] Curvature;
20084 
20085 }
20086 
20087 void CPhysicalGeometry::Compute_Nacelle(CConfig *config, bool original_surface,
20088  su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness,
20089  su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord,
20090  su2double &Nacelle_MaxMaxThickness, su2double &Nacelle_MinLERadius,
20091  su2double &Nacelle_MaxLERadius, su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC,
20092  su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist) {
20093 
20094  unsigned short iPlane, iDim, nPlane = 0;
20095  unsigned long iVertex;
20096  su2double Angle, MinAngle, MaxAngle, dAngle, *Area, *MaxThickness, *ToC, *Chord, *LERadius, *Twist;
20097  vector<su2double> *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil;
20098  ofstream Nacelle_File, Section_File;
20099 
20100 
20101  /*--- Make a large number of section cuts for approximating volume ---*/
20102 
20103  nPlane = config->GetnWingStations();
20104 
20105  /*--- Allocate memory for the section cutting ---*/
20106 
20107  Area = new su2double [nPlane];
20108  MaxThickness = new su2double [nPlane];
20109  Chord = new su2double [nPlane];
20110  LERadius = new su2double [nPlane];
20111  ToC = new su2double [nPlane];
20112  Twist = new su2double [nPlane];
20113 
20114  su2double **LeadingEdge = new su2double*[nPlane];
20115  for (iPlane = 0; iPlane < nPlane; iPlane++ )
20116  LeadingEdge[iPlane] = new su2double[nDim];
20117 
20118  su2double **TrailingEdge = new su2double*[nPlane];
20119  for (iPlane = 0; iPlane < nPlane; iPlane++ )
20120  TrailingEdge[iPlane] = new su2double[nDim];
20121 
20122  su2double **Plane_P0 = new su2double*[nPlane];
20123  for (iPlane = 0; iPlane < nPlane; iPlane++ )
20124  Plane_P0[iPlane] = new su2double[nDim];
20125 
20126  su2double **Plane_Normal = new su2double*[nPlane];
20127  for (iPlane = 0; iPlane < nPlane; iPlane++ )
20128  Plane_Normal[iPlane] = new su2double[nDim];
20129 
20130  MinAngle = config->GetStations_Bounds(0); MaxAngle = config->GetStations_Bounds(1);
20131  dAngle = fabs((MaxAngle - MinAngle)/su2double(nPlane-1));
20132 
20133  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20134  Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0;
20135  Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0;
20136  Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0;
20137 
20138  /*--- Apply roll to cut the nacelle ---*/
20139 
20140  Angle = MinAngle + iPlane*dAngle*PI_NUMBER/180.0;
20141 
20142  if (Angle <= 0) Angle = 1E-6;
20143  if (Angle >= 360) Angle = 359.999999;
20144 
20145  Plane_Normal[iPlane][0] = 0.0;
20146  Plane_Normal[iPlane][1] = -sin(Angle);
20147  Plane_Normal[iPlane][2] = cos(Angle);
20148 
20149  /*--- Apply tilt angle to the plane ---*/
20150 
20151  su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180;
20152  su2double Plane_NormalX_Tilt = Plane_Normal[iPlane][0]*cos(Tilt_Angle) + Plane_Normal[iPlane][2]*sin(Tilt_Angle);
20153  su2double Plane_NormalY_Tilt = Plane_Normal[iPlane][1];
20154  su2double Plane_NormalZ_Tilt = Plane_Normal[iPlane][2]*cos(Tilt_Angle) - Plane_Normal[iPlane][0]*sin(Tilt_Angle);
20155 
20156  /*--- Apply toe angle to the plane ---*/
20157 
20158  su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180;
20159  su2double Plane_NormalX_Tilt_Toe = Plane_NormalX_Tilt*cos(Toe_Angle) - Plane_NormalY_Tilt*sin(Toe_Angle);
20160  su2double Plane_NormalY_Tilt_Toe = Plane_NormalX_Tilt*sin(Toe_Angle) + Plane_NormalY_Tilt*cos(Toe_Angle);
20161  su2double Plane_NormalZ_Tilt_Toe = Plane_NormalZ_Tilt;
20162 
20163  /*--- Update normal vector ---*/
20164 
20165  Plane_Normal[iPlane][0] = Plane_NormalX_Tilt_Toe;
20166  Plane_Normal[iPlane][1] = Plane_NormalY_Tilt_Toe;
20167  Plane_Normal[iPlane][2] = Plane_NormalZ_Tilt_Toe;
20168 
20169  /*--- Point in the plane ---*/
20170 
20171  Plane_P0[iPlane][0] = config->GetNacelleLocation(0);
20172  Plane_P0[iPlane][1] = config->GetNacelleLocation(1);
20173  Plane_P0[iPlane][2] = config->GetNacelleLocation(2);
20174 
20175  }
20176 
20177  /*--- Allocate some vectors for storing airfoil coordinates ---*/
20178 
20179  Xcoord_Airfoil = new vector<su2double>[nPlane];
20180  Ycoord_Airfoil = new vector<su2double>[nPlane];
20181  Zcoord_Airfoil = new vector<su2double>[nPlane];
20182  Variable_Airfoil = new vector<su2double>[nPlane];
20183 
20184  /*--- Create the section slices through the geometry ---*/
20185 
20186  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20187 
20188  ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane],
20189  -1E6, 1E6, -1E6, 1E6, -1E6, 1E6, NULL, Xcoord_Airfoil[iPlane],
20190  Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane],
20191  Variable_Airfoil[iPlane], original_surface, config);
20192 
20193  }
20194 
20195  /*--- Compute airfoil characteristic only in the master node ---*/
20196 
20197  if (rank == MASTER_NODE) {
20198 
20199  /*--- Write an output file---*/
20200 
20201  if (config->GetOutput_FileFormat() == PARAVIEW) {
20202  Nacelle_File.open("nacelle_description.csv", ios::out);
20203  if (config->GetSystemMeasurements() == US)
20204  Nacelle_File << "\"Theta (deg)\",\"Area (in^2)\",\"Max. Thickness (in)\",\"Chord (in)\",\"Leading Edge Radius (1/in)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Leading Edge XLoc\",\"Leading Edge ZLoc\",\"Trailing Edge XLoc\",\"Trailing Edge ZLoc\"" << endl;
20205  else
20206  Nacelle_File << "\"Theta (deg)\",\"Area (m^2)\",\"Max. Thickness (m)\",\"Chord (m)\",\"Leading Edge Radius (1/m)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Curvature (1/in)\",\"Dihedral (deg)\",\"Leading Edge XLoc\",\"Leading Edge ZLoc\",\"Trailing Edge XLoc\",\"Trailing Edge ZLoc\"" << endl;
20207  }
20208  else {
20209  Nacelle_File.open("nacelle_description.dat", ios::out);
20210  Nacelle_File << "TITLE = \"Nacelle description\"" << endl;
20211  if (config->GetSystemMeasurements() == US)
20212  Nacelle_File << "VARIABLES = \"<greek>q</greek> (deg)\",\"Area (in<sup>2</sup>)\",\"Max. Thickness (in)\",\"Chord (in)\",\"Leading Edge Radius (1/in)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Leading Edge XLoc\",\"Leading Edge ZLoc\",\"Trailing Edge XLoc\",\"Trailing Edge ZLoc\"" << endl;
20213  else
20214  Nacelle_File << "VARIABLES = \"<greek>q</greek> (deg)\",\"Area (m<sup>2</sup>)\",\"Max. Thickness (m)\",\"Chord (m)\",\"Leading Edge Radius (1/m)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Leading Edge XLoc\",\"Leading Edge ZLoc\",\"Trailing Edge XLoc\",\"Trailing Edge ZLoc\"" << endl;
20215  Nacelle_File << "ZONE T= \"Baseline nacelle\"" << endl;
20216  }
20217 
20218 
20219  /*--- Evaluate geometrical quatities that do not require any kind of filter, local to each point ---*/
20220 
20221  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20222 
20223  for (iDim = 0; iDim < nDim; iDim++) {
20224  LeadingEdge[iPlane][iDim] = 0.0;
20225  TrailingEdge[iPlane][iDim] = 0.0;
20226  }
20227 
20228  Area[iPlane] = 0.0;
20229  MaxThickness[iPlane] = 0.0;
20230  Chord[iPlane] = 0.0;
20231  LERadius[iPlane] = 0.0;
20232  ToC[iPlane] = 0.0;
20233  Twist[iPlane] = 0.0;
20234 
20235  if (Xcoord_Airfoil[iPlane].size() > 1) {
20236 
20237  Compute_Wing_LeadingTrailing(LeadingEdge[iPlane], TrailingEdge[iPlane], Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20238 
20239  Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20240 
20241  MaxThickness[iPlane] = Compute_MaxThickness(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20242 
20243  Chord[iPlane] = Compute_Chord(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20244 
20245  Twist[iPlane] = Compute_Twist(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20246 
20247  LERadius[iPlane] = Compute_LERadius(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]);
20248 
20249  ToC[iPlane] = MaxThickness[iPlane] / Chord[iPlane];
20250 
20251 
20252  }
20253 
20254  }
20255 
20256  /*--- Plot the geometrical quatities ---*/
20257 
20258  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20259 
20260  su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180;
20261 
20262  if (Xcoord_Airfoil[iPlane].size() > 1) {
20263  if (config->GetOutput_FileFormat() == PARAVIEW) {
20264  Nacelle_File << theta_deg <<", "<< Area[iPlane] <<", "<< MaxThickness[iPlane] <<", "<< Chord[iPlane] <<", "<< LERadius[iPlane] <<", "<< ToC[iPlane]
20265  <<", "<< Twist[iPlane] <<", "<< LeadingEdge[iPlane][0] <<", "<< LeadingEdge[iPlane][2]
20266  <<", "<< TrailingEdge[iPlane][0] <<", "<< TrailingEdge[iPlane][2] << endl;
20267  }
20268  else {
20269  Nacelle_File << theta_deg <<" "<< Area[iPlane] <<" "<< MaxThickness[iPlane] <<" "<< Chord[iPlane] <<" "<< LERadius[iPlane] <<" "<< ToC[iPlane]
20270  <<" "<< Twist[iPlane] <<" "<< LeadingEdge[iPlane][0] <<" "<< LeadingEdge[iPlane][2]
20271  <<" "<< TrailingEdge[iPlane][0] <<" "<< TrailingEdge[iPlane][2] << endl;
20272 
20273  }
20274  }
20275 
20276  }
20277 
20278  Nacelle_File.close();
20279 
20280  Section_File.open("nacelle_slices.dat", ios::out);
20281 
20282  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20283 
20284  if (iPlane == 0) {
20285  Section_File << "TITLE = \"Nacelle Slices\"" << endl;
20286  if (config->GetSystemMeasurements() == US)
20287  Section_File << "VARIABLES = \"x (in)\", \"y (in)\", \"z (in)\", \"x<sub>2D</sub>/c\", \"y<sub>2D</sub>/c\"" << endl;
20288  else Section_File << "VARIABLES = \"x (m)\", \"y (m)\", \"z (m)\", \"x<sub>2D</sub>/c\", \"y<sub>2D</sub>/c\"" << endl;
20289  }
20290 
20291  if (Xcoord_Airfoil[iPlane].size() > 1) {
20292 
20293  su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180;
20294  su2double Angle = theta_deg*PI_NUMBER/180 - 0.5*PI_NUMBER;
20295 
20296  Section_File << "ZONE T=\"<greek>q</greek> = " << theta_deg << " deg\", I= " << Xcoord_Airfoil[iPlane].size() << ", F=POINT" << endl;
20297 
20298  for (iVertex = 0; iVertex < Xcoord_Airfoil[iPlane].size(); iVertex++) {
20299 
20300  /*--- Move to the origin ---*/
20301 
20302  su2double XValue_ = Xcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][0];
20303  su2double ZValue_ = Zcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][2];
20304 
20305  /*--- Rotate the airfoil and divide by the chord ---*/
20306 
20307  su2double ValCos = cos(Twist[iPlane]*PI_NUMBER/180.0);
20308  su2double ValSin = sin(Twist[iPlane]*PI_NUMBER/180.0);
20309 
20310  su2double XValue = (XValue_*ValCos - ZValue_*ValSin) / Chord[iPlane];
20311  su2double ZValue = (ZValue_*ValCos + XValue_*ValSin) / Chord[iPlane];
20312 
20313  su2double XCoord = Xcoord_Airfoil[iPlane][iVertex] + config->GetNacelleLocation(0);
20314  su2double YCoord = (Ycoord_Airfoil[iPlane][iVertex]*cos(Angle) - Zcoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(1);
20315  su2double ZCoord = (Zcoord_Airfoil[iPlane][iVertex]*cos(Angle) + Ycoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(2);
20316 
20317  /*--- Write the file ---*/
20318 
20319  Section_File << XCoord << " " << YCoord << " " << ZCoord << " " << XValue << " " << ZValue << endl;
20320  }
20321  }
20322 
20323  }
20324 
20325  Section_File.close();
20326 
20327 
20328  /*--- Compute the wing volume using a composite Simpson's rule ---*/
20329 
20330  Nacelle_Volume = 0.0;
20331  for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) {
20332  if (Xcoord_Airfoil[iPlane].size() > 1) {
20333  Nacelle_Volume += (1.0/3.0)*dAngle*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]);
20334  }
20335  }
20336 
20337  /*--- Evaluate Max and Min quantities ---*/
20338 
20339  Nacelle_MaxMaxThickness = -1E6; Nacelle_MinMaxThickness = 1E6; Nacelle_MinChord = 1E6; Nacelle_MaxChord = -1E6;
20340  Nacelle_MinLERadius = 1E6; Nacelle_MaxLERadius = -1E6; Nacelle_MinToC = 1E6; Nacelle_MaxToC = -1E6;
20341  Nacelle_MaxTwist = -1E6;
20342 
20343  for (iPlane = 0; iPlane < nPlane; iPlane++) {
20344  if (MaxThickness[iPlane] != 0.0) Nacelle_MinMaxThickness = min(Nacelle_MinMaxThickness, MaxThickness[iPlane]);
20345  Nacelle_MaxMaxThickness = max(Nacelle_MaxMaxThickness, MaxThickness[iPlane]);
20346  if (Chord[iPlane] != 0.0) Nacelle_MinChord = min(Nacelle_MinChord, Chord[iPlane]);
20347  Nacelle_MaxChord = max(Nacelle_MaxChord, Chord[iPlane]);
20348  if (LERadius[iPlane] != 0.0) Nacelle_MinLERadius = min(Nacelle_MinLERadius, LERadius[iPlane]);
20349  Nacelle_MaxLERadius = max(Nacelle_MaxLERadius, LERadius[iPlane]);
20350  if (ToC[iPlane] != 0.0) Nacelle_MinToC = min(Nacelle_MinToC, ToC[iPlane]);
20351  Nacelle_MaxToC = max(Nacelle_MaxToC, ToC[iPlane]);
20352  Nacelle_ObjFun_MinToC = sqrt((Nacelle_MinToC - 0.07)*(Nacelle_MinToC - 0.07));
20353  Nacelle_MaxTwist = max(Nacelle_MaxTwist, fabs(Twist[iPlane]));
20354  }
20355 
20356  }
20357 
20358  /*--- Free memory for the section cuts ---*/
20359 
20360  delete [] Xcoord_Airfoil;
20361  delete [] Ycoord_Airfoil;
20362  delete [] Zcoord_Airfoil;
20363  delete [] Variable_Airfoil;
20364 
20365  for (iPlane = 0; iPlane < nPlane; iPlane++)
20366  delete [] LeadingEdge[iPlane];
20367  delete [] LeadingEdge;
20368 
20369  for (iPlane = 0; iPlane < nPlane; iPlane++)
20370  delete [] TrailingEdge[iPlane];
20371  delete [] TrailingEdge;
20372 
20373  for (iPlane = 0; iPlane < nPlane; iPlane++)
20374  delete [] Plane_P0[iPlane];
20375  delete [] Plane_P0;
20376 
20377  for (iPlane = 0; iPlane < nPlane; iPlane++)
20378  delete [] Plane_Normal[iPlane];
20379  delete [] Plane_Normal;
20380 
20381  delete [] Area;
20382  delete [] MaxThickness;
20383  delete [] Chord;
20384  delete [] LERadius;
20385  delete [] ToC;
20386  delete [] Twist;
20387 
20388 }
20389 
20390 CMultiGridGeometry::CMultiGridGeometry(CGeometry ****geometry, CConfig **config_container, unsigned short iMesh, unsigned short iZone, unsigned short iInst) : CGeometry() {
20391 
20392  /*--- CGeometry & CConfig pointers to the fine grid level for clarity. We may
20393  need access to the other zones in the mesh for zone boundaries. ---*/
20394 
20395  CGeometry *fine_grid = geometry[iZone][iInst][iMesh-1];
20396  CConfig *config = config_container[iZone];
20397 
20398  /*--- Local variables ---*/
20399 
20400  unsigned long iPoint, Index_CoarseCV, CVPoint, iElem, iVertex, jPoint, iteration, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, iParent, jVertex, *Buffer_Receive_Parent = NULL, *Buffer_Send_Parent = NULL, *Buffer_Receive_Children = NULL, *Buffer_Send_Children = NULL, *Parent_Remote = NULL, *Children_Remote = NULL, *Parent_Local = NULL, *Children_Local = NULL, Local_nPointCoarse, Local_nPointFine, Global_nPointCoarse, Global_nPointFine;;
20401  short marker_seed;
20402  bool agglomerate_seed = true;
20403  unsigned short nChildren, iNode, counter, iMarker, jMarker, priority, MarkerS, MarkerR, *nChildren_MPI;
20404  vector<unsigned long> Suitable_Indirect_Neighbors, Aux_Parent;
20405  vector<unsigned long>::iterator it;
20406 
20407  unsigned short nMarker_Max = config->GetnMarker_Max();
20408 
20409  unsigned short *copy_marker = new unsigned short [nMarker_Max];
20410 
20411 #ifdef HAVE_MPI
20412  int send_to, receive_from;
20413  SU2_MPI::Status status;
20414 #endif
20415 
20416  nDim = fine_grid->GetnDim(); // Write the number of dimensions of the coarse grid.
20417 
20418  /*--- Create a queue system to deo the agglomeration
20419  1st) More than two markers ---> Vertices (never agglomerate)
20420  2nd) Two markers ---> Edges (agglomerate if same BC, never agglomerate if different BC)
20421  3rd) One marker ---> Surface (always agglomarate)
20422  4th) No marker ---> Internal Volume (always agglomarate) ---*/
20423 
20424  /*--- Set a marker to indicate indirect agglomeration ---*/
20425 
20426  if (iMesh == MESH_1) {
20427 
20428  for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++)
20429  fine_grid->node[iPoint]->SetAgglomerate_Indirect(false);
20430 
20431  for (iElem = 0; iElem < fine_grid->GetnElem(); iElem++) {
20432  if ((fine_grid->elem[iElem]->GetVTK_Type() == HEXAHEDRON) ||
20433  (fine_grid->elem[iElem]->GetVTK_Type() == QUADRILATERAL)) {
20434  for (iNode = 0; iNode < fine_grid->elem[iElem]->GetnNodes(); iNode++) {
20435  iPoint = fine_grid->elem[iElem]->GetNode(iNode);
20436  fine_grid->node[iPoint]->SetAgglomerate_Indirect(true);
20437  }
20438  }
20439  }
20440 
20441  }
20442 
20443  /*--- Create the coarse grid structure using as baseline the fine grid ---*/
20444 
20445  CMultiGridQueue MGQueue_InnerCV(fine_grid->GetnPoint());
20446 
20447  nPointNode = fine_grid->GetnPoint();
20448  node = new CPoint*[fine_grid->GetnPoint()];
20449  for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) {
20450 
20451  /*--- Create node structure ---*/
20452 
20453  node[iPoint] = new CPoint(nDim, iPoint, config);
20454 
20455  /*--- Set the indirect agglomeration to false ---*/
20456 
20457  node[iPoint]->SetAgglomerate_Indirect(false);
20458  }
20459 
20460  Index_CoarseCV = 0;
20461 
20462  /*--- The first step is the boundary agglomeration. ---*/
20463 
20464  for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) {
20465 
20466  for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) {
20467  iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode();
20468 
20469  /*--- If the element has not being previously agglomerated and it belongs
20470  to the physical domain, then the agglomeration is studied ---*/
20471 
20472  if ((fine_grid->node[iPoint]->GetAgglomerate() == false) &&
20473  (fine_grid->node[iPoint]->GetDomain()) &&
20474  (GeometricalCheck(iPoint, fine_grid, config))) {
20475 
20476  nChildren = 1;
20477 
20478  /*--- We set an index for the parent control volume ---*/
20479 
20480  fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV);
20481 
20482  /*--- We add the seed point (child) to the parent control volume ---*/
20483 
20484  node[Index_CoarseCV]->SetChildren_CV(0, iPoint);
20485  agglomerate_seed = true; counter = 0; marker_seed = iMarker;
20486 
20487  /*--- For a particular point in the fine grid we save all the markers
20488  that are in that point ---*/
20489 
20490  for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++)
20491  if (fine_grid->node[iPoint]->GetVertex(jMarker) != -1) {
20492  copy_marker[counter] = jMarker;
20493  counter++;
20494  }
20495 
20496  /*--- To aglomerate a vertex it must have only one physical bc!!
20497  This can be improved. If there is only a marker, it is a good
20498  candidate for agglomeration ---*/
20499 
20500  if (counter == 1) agglomerate_seed = true;
20501 
20502  /*--- If there are two markers, we will aglomerate if one of the
20503  marker is SEND_RECEIVE ---*/
20504 
20505  if (counter == 2) {
20506  if ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) ||
20507  (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) agglomerate_seed = true;
20508  else agglomerate_seed = false;
20509  }
20510 
20511  /*--- If there are more than 2 markers, the aglomeration will be discarted ---*/
20512 
20513  if (counter > 2) agglomerate_seed = false;
20514 
20515  /*--- If the seed can be agglomerated, we try to agglomerate more points ---*/
20516 
20517  if (agglomerate_seed) {
20518 
20519  /*--- Now we do a sweep over all the nodes that surround the seed point ---*/
20520 
20521  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
20522 
20523  CVPoint = fine_grid->node[iPoint]->GetPoint(iNode);
20524 
20525  /*--- The new point can be agglomerated ---*/
20526 
20527  if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) {
20528 
20529  /*--- We set the value of the parent ---*/
20530 
20531  fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV);
20532 
20533  /*--- We set the value of the child ---*/
20534 
20535  node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint);
20536  nChildren++;
20537  }
20538 
20539  }
20540 
20541  Suitable_Indirect_Neighbors.clear();
20542 
20543  if (fine_grid->node[iPoint]->GetAgglomerate_Indirect())
20544  SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid);
20545 
20546  /*--- Now we do a sweep over all the indirect nodes that can be added ---*/
20547 
20548  for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) {
20549 
20550  CVPoint = Suitable_Indirect_Neighbors[iNode];
20551 
20552  /*--- The new point can be agglomerated ---*/
20553 
20554  if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) {
20555 
20556  /*--- We set the value of the parent ---*/
20557 
20558  fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV);
20559 
20560  /*--- We set the indirect agglomeration information ---*/
20561 
20562  if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect())
20563  node[Index_CoarseCV]->SetAgglomerate_Indirect(true);
20564 
20565  /*--- We set the value of the child ---*/
20566 
20567  node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint);
20568  nChildren++;
20569  }
20570  }
20571 
20572 
20573  }
20574 
20575  /*--- Update the number of child of the control volume ---*/
20576 
20577  node[Index_CoarseCV]->SetnChildren_CV(nChildren);
20578  Index_CoarseCV++;
20579  }
20580  }
20581  }
20582 
20583  /*--- Agglomerate all the nodes that have more than one physical boundary condition,
20584  Maybe here we can add the posibility of merging the vertex that have the same number,
20585  and kind of markers---*/
20586 
20587  for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++)
20588  for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) {
20589  iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode();
20590  if ((fine_grid->node[iPoint]->GetAgglomerate() == false) &&
20591  (fine_grid->node[iPoint]->GetDomain())) {
20592  fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV);
20593  node[Index_CoarseCV]->SetChildren_CV(0, iPoint);
20594  node[Index_CoarseCV]->SetnChildren_CV(1);
20595  Index_CoarseCV++;
20596  }
20597  }
20598 
20599  /*--- Update the queue with the results from the boundary agglomeration ---*/
20600 
20601  for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) {
20602 
20603  /*--- The CV has been agglomerated, remove form the list ---*/
20604 
20605  if (fine_grid->node[iPoint]->GetAgglomerate() == true) {
20606 
20607  MGQueue_InnerCV.RemoveCV(iPoint);
20608 
20609  }
20610 
20611  else {
20612 
20613  /*--- Count the number of agglomerated neighbors, and modify the queue ---*/
20614 
20615  priority = 0;
20616  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
20617  jPoint = fine_grid->node[iPoint]->GetPoint(iNode);
20618  if (fine_grid->node[jPoint]->GetAgglomerate() == true) priority++;
20619  }
20620  MGQueue_InnerCV.MoveCV(iPoint, priority);
20621  }
20622  }
20623 
20624  /*--- Agglomerate the domain nodes ---*/
20625 
20626  iteration = 0;
20627  while (!MGQueue_InnerCV.EmptyQueue() && (iteration < fine_grid->GetnPoint())) {
20628 
20629  iPoint = MGQueue_InnerCV.NextCV();
20630  iteration ++;
20631 
20632  /*--- If the element has not being previously agglomerated, belongs to the physical domain,
20633  and satisfies several geometrical criteria then the seed CV is acepted for agglomeration ---*/
20634 
20635  if ((fine_grid->node[iPoint]->GetAgglomerate() == false) &&
20636  (fine_grid->node[iPoint]->GetDomain()) &&
20637  (GeometricalCheck(iPoint, fine_grid, config))) {
20638 
20639  nChildren = 1;
20640 
20641  /*--- We set an index for the parent control volume ---*/
20642 
20643  fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV);
20644 
20645  /*--- We add the seed point (child) to the parent control volume ---*/
20646 
20647  node[Index_CoarseCV]->SetChildren_CV(0, iPoint);
20648 
20649  /*--- Update the queue with the seed point (remove the seed and
20650  increase the priority of the neighbors) ---*/
20651 
20652  MGQueue_InnerCV.Update(iPoint, fine_grid);
20653 
20654  /*--- Now we do a sweep over all the nodes that surround the seed point ---*/
20655 
20656  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
20657 
20658  CVPoint = fine_grid->node[iPoint]->GetPoint(iNode);
20659 
20660  /*--- Determine if the CVPoint can be agglomerated ---*/
20661 
20662  if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) &&
20663  (fine_grid->node[CVPoint]->GetDomain()) &&
20664  (GeometricalCheck(CVPoint, fine_grid, config))) {
20665 
20666  /*--- We set the value of the parent ---*/
20667 
20668  fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV);
20669 
20670  /*--- We set the value of the child ---*/
20671 
20672  node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint);
20673  nChildren++;
20674 
20675  /*--- Update the queue with the new control volume (remove the CV and
20676  increase the priority of the neighbors) ---*/
20677 
20678  MGQueue_InnerCV.Update(CVPoint, fine_grid);
20679 
20680  }
20681 
20682  }
20683 
20684  /*--- Subrotuine to identify the indirect neighbors ---*/
20685 
20686  Suitable_Indirect_Neighbors.clear();
20687  if (fine_grid->node[iPoint]->GetAgglomerate_Indirect())
20688  SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid);
20689 
20690  /*--- Now we do a sweep over all the indirect nodes that can be added ---*/
20691 
20692  for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) {
20693 
20694  CVPoint = Suitable_Indirect_Neighbors[iNode];
20695 
20696  /*--- The new point can be agglomerated ---*/
20697 
20698  if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) &&
20699  (fine_grid->node[CVPoint]->GetDomain())) {
20700 
20701  /*--- We set the value of the parent ---*/
20702 
20703  fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV);
20704 
20705  /*--- We set the indirect agglomeration information ---*/
20706 
20707  if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect())
20708  node[Index_CoarseCV]->SetAgglomerate_Indirect(true);
20709 
20710  /*--- We set the value of the child ---*/
20711 
20712  node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint);
20713  nChildren++;
20714 
20715  /*--- Update the queue with the new control volume (remove the CV and
20716  increase the priority of the neighbors) ---*/
20717 
20718  MGQueue_InnerCV.Update(CVPoint, fine_grid);
20719 
20720  }
20721  }
20722 
20723  /*--- Update the number of control of childrens ---*/
20724 
20725  node[Index_CoarseCV]->SetnChildren_CV(nChildren);
20726  Index_CoarseCV++;
20727  }
20728  else {
20729 
20730  /*--- The seed point can not be agglomerated because of size, domain, streching, etc.
20731  move the point to the lowest priority ---*/
20732 
20733  MGQueue_InnerCV.MoveCV(iPoint, -1);
20734  }
20735 
20736  }
20737 
20738  /*--- Add all the elements that have not being agglomerated, in the previous stage ---*/
20739 
20740  for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) {
20741  if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && (fine_grid->node[iPoint]->GetDomain())) {
20742 
20743  nChildren = 1;
20744  fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV);
20745  if (fine_grid->node[iPoint]->GetAgglomerate_Indirect())
20746  node[Index_CoarseCV]->SetAgglomerate_Indirect(true);
20747  node[Index_CoarseCV]->SetChildren_CV(0, iPoint);
20748  node[Index_CoarseCV]->SetnChildren_CV(nChildren);
20749  Index_CoarseCV++;
20750 
20751  }
20752  }
20753 
20754  nPointDomain = Index_CoarseCV;
20755 
20756  /*--- Check that there are no hanging nodes ---*/
20757 
20758  unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iCoarsePoint_Complete;
20759  unsigned short iChildren;
20760 
20761  /*--- Find the point surrounding a point ---*/
20762 
20763  for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) {
20764  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
20765  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
20766  for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) {
20767  iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode);
20768  iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV();
20769  if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent);
20770  }
20771  }
20772  }
20773 
20774  /*--- Detect isolated points and merge them with its correct neighbor ---*/
20775 
20776  for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) {
20777 
20778  if (node[iCoarsePoint]->GetnPoint() == 1) {
20779 
20780  /*--- Find the neighbor of the isolated point. This neighbor is the right control volume ---*/
20781 
20782  iCoarsePoint_Complete = node[iCoarsePoint]->GetPoint(0);
20783 
20784  /*--- Add the children to the connected control volume (and modify it parent indexing).
20785  Identify the child CV from the finest grid and added to the correct control volume.
20786  Set the parent CV of iFinePoint. Instead of using the original
20787  (iCoarsePoint) one use the new one (iCoarsePoint_Complete) ---*/
20788 
20789  nChildren = node[iCoarsePoint_Complete]->GetnChildren_CV();
20790 
20791  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
20792  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
20793  node[iCoarsePoint_Complete]->SetChildren_CV(nChildren, iFinePoint);
20794  nChildren++;
20795  fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint_Complete);
20796  }
20797 
20798  /*--- Update the number of children control volumes ---*/
20799 
20800  node[iCoarsePoint_Complete]->SetnChildren_CV(nChildren);
20801  node[iCoarsePoint]->SetnChildren_CV(0);
20802 
20803  }
20804  }
20805 
20806  // unsigned long iPointFree = nPointDomain-1;
20807  // iCoarsePoint = 0;
20808  //
20809  // do {
20810  //
20811  // if (node[iCoarsePoint]->GetnChildren_CV() == 0) {
20812  //
20813  // while (node[iPointFree]->GetnChildren_CV() == 0) {
20814  // Index_CoarseCV--;
20815  // iPointFree--;
20816  // }
20817  //
20818  // nChildren = node[iPointFree]->GetnChildren_CV();
20819  // for (iChildren = 0; iChildren < nChildren; iChildren ++) {
20820  // iFinePoint = node[iPointFree]->GetChildren_CV(iChildren);
20821  // node[iCoarsePoint]->SetChildren_CV(iChildren, iFinePoint);
20822  // fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint);
20823  // }
20824  // node[iCoarsePoint]->SetnChildren_CV(nChildren);
20825  // node[iPointFree]->SetnChildren_CV(0);
20826  //
20827  // Index_CoarseCV--;
20828  // iPointFree--;
20829  //
20830  // }
20831  //
20832  // iCoarsePoint++;
20833  //
20834  // } while ((iCoarsePoint-1) < Index_CoarseCV);
20835  //
20836  // nPointDomain = Index_CoarseCV;
20837 
20838  /*--- Reset the point surrounding a point ---*/
20839 
20840  for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) {
20841  node[iCoarsePoint]->ResetPoint();
20842  }
20843 
20844  /*--- Dealing with MPI parallelization, the objective is that the received nodes must be agglomerated
20845  in the same way as the donor nodes. Send the node agglomeration information of the donor
20846  (parent and children), Sending only occurs with MPI ---*/
20847 
20848  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
20849 
20850  if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) &&
20851  (config->GetMarker_All_SendRecv(iMarker) > 0)) {
20852 
20853  MarkerS = iMarker; MarkerR = iMarker+1;
20854 
20855 #ifdef HAVE_MPI
20856  send_to = config->GetMarker_All_SendRecv(MarkerS)-1;
20857  receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1;
20858 #endif
20859 
20860  nVertexS = fine_grid->nVertex[MarkerS]; nVertexR = fine_grid->nVertex[MarkerR];
20861  nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR;
20862 
20863  /*--- Allocate Receive and send buffers ---*/
20864 
20865  Buffer_Receive_Children = new unsigned long [nBufferR_Vector];
20866  Buffer_Send_Children = new unsigned long [nBufferS_Vector];
20867 
20868  Buffer_Receive_Parent = new unsigned long [nBufferR_Vector];
20869  Buffer_Send_Parent = new unsigned long [nBufferS_Vector];
20870 
20871  /*--- Copy the information that should be sended ---*/
20872 
20873  for (iVertex = 0; iVertex < nVertexS; iVertex++) {
20874  iPoint = fine_grid->vertex[MarkerS][iVertex]->GetNode();
20875  Buffer_Send_Children[iVertex] = iPoint;
20876  Buffer_Send_Parent[iVertex] = fine_grid->node[iPoint]->GetParent_CV();
20877  }
20878 
20879 #ifdef HAVE_MPI
20880  /*--- Send/Receive information using Sendrecv ---*/
20881  SU2_MPI::Sendrecv(Buffer_Send_Children, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,0,
20882  Buffer_Receive_Children, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,0, MPI_COMM_WORLD, &status);
20883  SU2_MPI::Sendrecv(Buffer_Send_Parent, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,1,
20884  Buffer_Receive_Parent, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,1, MPI_COMM_WORLD, &status);
20885 #else
20886  /*--- Receive information without MPI ---*/
20887  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
20888  Buffer_Receive_Children[iVertex] = Buffer_Send_Children[iVertex];
20889  Buffer_Receive_Parent[iVertex] = Buffer_Send_Parent[iVertex];
20890  }
20891 #endif
20892 
20893  /*--- Deallocate send buffer ---*/
20894 
20895  delete [] Buffer_Send_Children;
20896  delete [] Buffer_Send_Parent;
20897 
20898  /*--- Create a list of the parent nodes without repeated parents ---*/
20899 
20900  Aux_Parent.clear();
20901  for (iVertex = 0; iVertex < nVertexR; iVertex++)
20902  Aux_Parent.push_back (Buffer_Receive_Parent[iVertex]);
20903 
20904  sort(Aux_Parent.begin(), Aux_Parent.end());
20905  it = unique(Aux_Parent.begin(), Aux_Parent.end());
20906  Aux_Parent.resize(it - Aux_Parent.begin());
20907 
20908  /*--- Allocate some structures ---*/
20909 
20910  Parent_Remote = new unsigned long[nVertexR];
20911  Children_Remote = new unsigned long[nVertexR];
20912  Parent_Local = new unsigned long[nVertexR];
20913  Children_Local = new unsigned long[nVertexR];
20914 
20915  /*--- Create the local vector and remote for the parents and the children ---*/
20916 
20917  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
20918 
20919  Parent_Remote[iVertex] = Buffer_Receive_Parent[iVertex];
20920 
20921  /*--- We use the same sorting as in the donor domain ---*/
20922 
20923  for (jVertex = 0; jVertex < Aux_Parent.size(); jVertex++) {
20924  if (Parent_Remote[iVertex] == Aux_Parent[jVertex]) {
20925  Parent_Local[iVertex] = jVertex + Index_CoarseCV;
20926  break;
20927  }
20928  }
20929 
20930  Children_Remote[iVertex] = Buffer_Receive_Children[iVertex];
20931  Children_Local[iVertex] = fine_grid->vertex[MarkerR][iVertex]->GetNode();
20932 
20933  }
20934 
20935  Index_CoarseCV += Aux_Parent.size();
20936 
20937  nChildren_MPI = new unsigned short [Index_CoarseCV];
20938  for (iParent = 0; iParent < Index_CoarseCV; iParent++)
20939  nChildren_MPI[iParent] = 0;
20940 
20941  /*--- Create the final structure ---*/
20942  for (iVertex = 0; iVertex < nVertexR; iVertex++) {
20943 
20944  /*--- Be careful, it is possible that a node change the agglomeration configuration, the priority
20945  is always, when receive the information ---*/
20946 
20947  fine_grid->node[Children_Local[iVertex]]->SetParent_CV(Parent_Local[iVertex]);
20948  node[Parent_Local[iVertex]]->SetChildren_CV(nChildren_MPI[Parent_Local[iVertex]], Children_Local[iVertex]);
20949  nChildren_MPI[Parent_Local[iVertex]]++;
20950  node[Parent_Local[iVertex]]->SetnChildren_CV(nChildren_MPI[Parent_Local[iVertex]]);
20951  node[Parent_Local[iVertex]]->SetDomain(false);
20952 
20953  }
20954 
20955  /*--- Deallocate auxiliar structures ---*/
20956 
20957  delete[] nChildren_MPI;
20958  delete[] Parent_Remote;
20959  delete[] Children_Remote;
20960  delete[] Parent_Local;
20961  delete[] Children_Local;
20962 
20963  /*--- Deallocate receive buffer ---*/
20964 
20965  delete [] Buffer_Receive_Children;
20966  delete [] Buffer_Receive_Parent;
20967 
20968  }
20969 
20970  }
20971 
20972  /*--- Update the number of points after the MPI agglomeration ---*/
20973 
20974  nPoint = Index_CoarseCV;
20975 
20976  /*--- Console output with the summary of the agglomeration ---*/
20977 
20978  Local_nPointCoarse = nPoint;
20979  Local_nPointFine = fine_grid->GetnPoint();
20980 
20981 #ifdef HAVE_MPI
20982  SU2_MPI::Allreduce(&Local_nPointCoarse, &Global_nPointCoarse, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
20983  SU2_MPI::Allreduce(&Local_nPointFine, &Global_nPointFine, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
20984 #else
20985  Global_nPointCoarse = Local_nPointCoarse;
20986  Global_nPointFine = Local_nPointFine;
20987 #endif
20988 
20989  su2double Coeff = 1.0, CFL = 0.0, factor = 1.5;
20990 
20991  if (iMesh != MESH_0) {
20992  if (nDim == 2) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./2.);
20993  if (nDim == 3) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./3.);
20994  CFL = factor*config->GetCFL(iMesh-1)/Coeff;
20995  config->SetCFL(iMesh, CFL);
20996  }
20997 
20998  su2double ratio = su2double(Global_nPointFine)/su2double(Global_nPointCoarse);
20999 
21000  if (((nDim == 2) && (ratio < 2.5)) ||
21001  ((nDim == 3) && (ratio < 2.5))) {
21002  config->SetMGLevels(iMesh-1);
21003  }
21004  else {
21005  if (rank == MASTER_NODE) {
21006  if (iMesh == 1) cout <<"MG level: "<< iMesh-1 <<" -> CVs: " << Global_nPointFine << ". Agglomeration rate 1/1.00. CFL "<< config->GetCFL(iMesh-1) <<"." << endl;
21007  cout <<"MG level: "<< iMesh <<" -> CVs: " << Global_nPointCoarse << ". Agglomeration rate 1/" << ratio <<". CFL "<< CFL <<"." << endl;
21008  }
21009  }
21010 
21011  delete [] copy_marker;
21012 
21013 }
21014 
21015 
21017 
21018 }
21019 
21020 bool CMultiGridGeometry::SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config) {
21021 
21022  bool agglomerate_CV = false;
21023  unsigned short counter, jMarker;
21024 
21025  unsigned short nMarker_Max = config->GetnMarker_Max();
21026 
21027  unsigned short *copy_marker = new unsigned short [nMarker_Max];
21028 
21029  /*--- Basic condition, the element has not being previously agglomerated, it belongs to the domain,
21030  and has passed some basic geometrical check ---*/
21031 
21032  if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) &&
21033  (fine_grid->node[CVPoint]->GetDomain()) &&
21034  (GeometricalCheck(CVPoint, fine_grid, config))) {
21035 
21036  /*--- If the element belong to the boundary, we must be careful ---*/
21037 
21038  if (fine_grid->node[CVPoint]->GetBoundary()) {
21039 
21040  /*--- Identify the markers of the vertex that we want to agglomerate ---*/
21041 
21042  counter = 0;
21043  for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++)
21044  if (fine_grid->node[CVPoint]->GetVertex(jMarker) != -1) {
21045  copy_marker[counter] = jMarker;
21046  counter++;
21047  }
21048 
21049  /*--- The basic condition is that the aglomerated vertex must have the same physical marker,
21050  but eventually a send-receive condition ---*/
21051 
21052  /*--- Only one marker in the vertex that is going to be aglomerated ---*/
21053 
21054  if (counter == 1) {
21055 
21056  /*--- We agglomerate if there is only a marker and is the same marker as the seed marker ---*/
21057 
21058  if (copy_marker[0] == marker_seed)
21059  agglomerate_CV = true;
21060 
21061  /*--- If there is only a marker, but the marker is the SEND_RECEIVE ---*/
21062 
21063  if (config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE)
21064  agglomerate_CV = true;
21065 
21066  }
21067 
21068  /*--- If there are two markers in the vertex that is going to be aglomerated ---*/
21069 
21070  if (counter == 2) {
21071 
21072  /*--- First we verify that the seed is a physical boundary ---*/
21073 
21074  if (config->GetMarker_All_KindBC(marker_seed) != SEND_RECEIVE) {
21075 
21076  /*--- Then we check that one of the marker is equal to the seed marker, and the other is send/receive ---*/
21077 
21078  if (((copy_marker[0] == marker_seed) && (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) ||
21079  ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) && (copy_marker[1] == marker_seed)))
21080  agglomerate_CV = true;
21081  }
21082 
21083  }
21084 
21085  }
21086 
21087  /*--- If the element belong to the domain, it is allways aglomerated ---*/
21088 
21089  else { agglomerate_CV = true; }
21090 
21091  }
21092 
21093  delete [] copy_marker;
21094 
21095  return agglomerate_CV;
21096 
21097 }
21098 
21099 
21100 bool CMultiGridGeometry::GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config) {
21101 
21102  su2double max_dimension = 1.2;
21103 
21104  /*--- Evaluate the total size of the element ---*/
21105 
21106  bool Volume = true;
21107  su2double ratio = pow(fine_grid->node[iPoint]->GetVolume(), 1.0/su2double(nDim))*max_dimension;
21108  su2double limit = pow(config->GetDomainVolume(), 1.0/su2double(nDim));
21109  if ( ratio > limit ) Volume = false;
21110 
21111  /*--- Evaluate the stretching of the element ---*/
21112 
21113  bool Stretching = true;
21114 
21115  /* unsigned short iNode, iDim;
21116  unsigned long jPoint;
21117  su2double *Coord_i = fine_grid->node[iPoint]->GetCoord();
21118  su2double max_dist = 0.0 ; su2double min_dist = 1E20;
21119  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
21120  jPoint = fine_grid->node[iPoint]->GetPoint(iNode);
21121  su2double *Coord_j = fine_grid->node[jPoint]->GetCoord();
21122  su2double distance = 0.0;
21123  for (iDim = 0; iDim < nDim; iDim++)
21124  distance += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]);
21125  distance = sqrt(distance);
21126  max_dist = max(distance, max_dist);
21127  min_dist = min(distance, min_dist);
21128  }
21129  if ( max_dist/min_dist > 100.0 ) Stretching = false;*/
21130 
21131  return (Stretching && Volume);
21132 
21133 }
21134 
21135 void CMultiGridGeometry::SetSuitableNeighbors(vector<unsigned long> *Suitable_Indirect_Neighbors, unsigned long iPoint,
21136  unsigned long Index_CoarseCV, CGeometry *fine_grid) {
21137 
21138  unsigned long jPoint, kPoint, lPoint;
21139  unsigned short iNode, jNode, iNeighbor, jNeighbor, kNode;
21140  bool SecondNeighborSeed, ThirdNeighborSeed;
21141  vector<unsigned long>::iterator it;
21142 
21143  /*--- Create a list with the first neighbors, including the seed ---*/
21144 
21145  vector<unsigned long> First_Neighbor_Points;
21146  First_Neighbor_Points.push_back(iPoint);
21147  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
21148  jPoint = fine_grid->node[iPoint]->GetPoint(iNode);
21149  First_Neighbor_Points.push_back(jPoint);
21150  }
21151 
21152  /*--- Create a list with the second neighbors, without first, and seed neighbors ---*/
21153 
21154  vector<unsigned long> Second_Neighbor_Points, Second_Origin_Points, Suitable_Second_Neighbors;
21155 
21156  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
21157  jPoint = fine_grid->node[iPoint]->GetPoint(iNode);
21158 
21159  for (jNode = 0; jNode < fine_grid->node[jPoint]->GetnPoint(); jNode ++) {
21160  kPoint = fine_grid->node[jPoint]->GetPoint(jNode);
21161 
21162  /*--- Check that the second neighbor do not belong to the first neighbor or the seed ---*/
21163 
21164  SecondNeighborSeed = true;
21165  for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++)
21166  if (kPoint == First_Neighbor_Points[iNeighbor]) {
21167  SecondNeighborSeed = false; break;
21168  }
21169 
21170  if (SecondNeighborSeed) {
21171  Second_Neighbor_Points.push_back(kPoint);
21172  Second_Origin_Points.push_back(jPoint);
21173  }
21174 
21175  }
21176  }
21177 
21178  /*--- Identify those second neighbors that are repeated (candidate to be added) ---*/
21179 
21180  for (iNeighbor = 0; iNeighbor < Second_Neighbor_Points.size(); iNeighbor ++)
21181 
21182  for (jNeighbor = 0; jNeighbor < Second_Neighbor_Points.size(); jNeighbor ++)
21183 
21184  /*--- Repeated second neighbor with different origin ---*/
21185 
21186  if ((Second_Neighbor_Points[iNeighbor] == Second_Neighbor_Points[jNeighbor]) &&
21187  (Second_Origin_Points[iNeighbor] != Second_Origin_Points[jNeighbor]) &&
21188  (iNeighbor < jNeighbor)) {
21189 
21190  Suitable_Indirect_Neighbors->push_back(Second_Neighbor_Points[iNeighbor]);
21191 
21192  /*--- Create alist with the suitable second neighbor, that we will use
21193  to compute the third neighbors --*/
21194 
21195  Suitable_Second_Neighbors.push_back(Second_Neighbor_Points[iNeighbor]);
21196 
21197  }
21198 
21199 
21200  /*--- Remove repeated from the suitable second neighbors ---*/
21201 
21202  sort(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end());
21203  it = unique(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end());
21204  Suitable_Second_Neighbors.resize(it - Suitable_Second_Neighbors.begin());
21205 
21206  /*--- Remove repeated from first neighbors ---*/
21207 
21208  sort(First_Neighbor_Points.begin(), First_Neighbor_Points.end());
21209  it = unique(First_Neighbor_Points.begin(), First_Neighbor_Points.end());
21210  First_Neighbor_Points.resize(it - First_Neighbor_Points.begin());
21211 
21212  /*--- Create a list with the third neighbors, without first, second, and seed neighbors ---*/
21213 
21214  vector<unsigned long> Third_Neighbor_Points, Third_Origin_Points;
21215 
21216  for (jNode = 0; jNode < Suitable_Second_Neighbors.size(); jNode ++) {
21217  kPoint = Suitable_Second_Neighbors[jNode];
21218 
21219  for (kNode = 0; kNode < fine_grid->node[kPoint]->GetnPoint(); kNode ++) {
21220  lPoint = fine_grid->node[kPoint]->GetPoint(kNode);
21221 
21222  /*--- Check that the third neighbor do not belong to the first neighbors or the seed ---*/
21223 
21224  ThirdNeighborSeed = true;
21225 
21226  for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++)
21227  if (lPoint == First_Neighbor_Points[iNeighbor]) {
21228  ThirdNeighborSeed = false;
21229  break;
21230  }
21231 
21232  /*--- Check that the third neighbor do not belong to the second neighbors ---*/
21233 
21234  for (iNeighbor = 0; iNeighbor < Suitable_Second_Neighbors.size(); iNeighbor ++)
21235  if (lPoint == Suitable_Second_Neighbors[iNeighbor]) {
21236  ThirdNeighborSeed = false;
21237  break;
21238  }
21239 
21240  if (ThirdNeighborSeed) {
21241  Third_Neighbor_Points.push_back(lPoint);
21242  Third_Origin_Points.push_back(kPoint);
21243  }
21244 
21245  }
21246  }
21247 
21248  /*--- Identify those third neighbors that are repeated (candidate to be added) ---*/
21249 
21250  for (iNeighbor = 0; iNeighbor < Third_Neighbor_Points.size(); iNeighbor ++)
21251  for (jNeighbor = 0; jNeighbor < Third_Neighbor_Points.size(); jNeighbor ++)
21252 
21253  /*--- Repeated second neighbor with different origin ---*/
21254 
21255  if ((Third_Neighbor_Points[iNeighbor] == Third_Neighbor_Points[jNeighbor]) &&
21256  (Third_Origin_Points[iNeighbor] != Third_Origin_Points[jNeighbor]) &&
21257  (iNeighbor < jNeighbor)) {
21258 
21259  Suitable_Indirect_Neighbors->push_back(Third_Neighbor_Points[iNeighbor]);
21260 
21261  }
21262 
21263  /*--- Remove repeated from Suitable Indirect Neighbors List ---*/
21264 
21265  sort(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end());
21266  it = unique(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end());
21267  Suitable_Indirect_Neighbors->resize(it - Suitable_Indirect_Neighbors->begin());
21268 
21269 }
21270 
21272 
21273  unsigned long iFinePoint, iFinePoint_Neighbor, iParent, iCoarsePoint;
21274  unsigned short iChildren, iNode;
21275 
21276  /*--- Set the point surrounding a point ---*/
21277 
21278  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) {
21279  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21280  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21281  for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) {
21282  iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode);
21283  iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV();
21284  if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent);
21285  }
21286  }
21287  }
21288 
21289  /*--- Set the number of neighbors variable, this is
21290  important for JST and multigrid in parallel ---*/
21291 
21292  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++)
21293  node[iCoarsePoint]->SetnNeighbor(node[iCoarsePoint]->GetnPoint());
21294 
21295 }
21296 
21298  unsigned long iVertex, iFinePoint, iCoarsePoint;
21299  unsigned short iMarker, iMarker_Tag, iChildren;
21300 
21301  nMarker = fine_grid->GetnMarker();
21302  unsigned short nMarker_Max = config->GetnMarker_Max();
21303 
21304  /*--- If any children node belong to the boundary then the entire control
21305  volume will belong to the boundary ---*/
21306  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++)
21307  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21308  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21309  if (fine_grid->node[iFinePoint]->GetBoundary()) {
21310  node[iCoarsePoint]->SetBoundary(nMarker);
21311  break;
21312  }
21313  }
21314 
21315  vertex = new CVertex**[nMarker];
21316  nVertex = new unsigned long [nMarker];
21317 
21318  Tag_to_Marker = new string [nMarker_Max];
21319  for (iMarker_Tag = 0; iMarker_Tag < nMarker_Max; iMarker_Tag++)
21320  Tag_to_Marker[iMarker_Tag] = fine_grid->GetMarker_Tag(iMarker_Tag);
21321 
21322  /*--- Compute the number of vertices to do the dimensionalization ---*/
21323  for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0;
21324 
21325 
21326  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) {
21327  if (node[iCoarsePoint]->GetBoundary()) {
21328  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21329  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21330  for (iMarker = 0; iMarker < nMarker; iMarker ++) {
21331  if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) {
21332  iVertex = nVertex[iMarker];
21333  node[iCoarsePoint]->SetVertex(iVertex, iMarker);
21334  nVertex[iMarker]++;
21335  }
21336  }
21337  }
21338  }
21339  }
21340 
21341  for (iMarker = 0; iMarker < nMarker; iMarker++) {
21342  vertex[iMarker] = new CVertex* [fine_grid->GetnVertex(iMarker)+1];
21343  nVertex[iMarker] = 0;
21344  }
21345 
21346  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++)
21347  if (node[iCoarsePoint]->GetBoundary())
21348  for (iMarker = 0; iMarker < nMarker; iMarker ++)
21349  node[iCoarsePoint]->SetVertex(-1, iMarker);
21350 
21351  for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0;
21352 
21353  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++)
21354  if (node[iCoarsePoint]->GetBoundary())
21355  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21356  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21357  for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker ++) {
21358  if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) {
21359  iVertex = nVertex[iMarker];
21360  vertex[iMarker][iVertex] = new CVertex(iCoarsePoint, nDim);
21361  node[iCoarsePoint]->SetVertex(iVertex, iMarker);
21362 
21363  /*--- Set the transformation to apply ---*/
21364  unsigned long ChildVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker);
21365  unsigned short RotationKind = fine_grid->vertex[iMarker][ChildVertex]->GetRotation_Type();
21366  vertex[iMarker][iVertex]->SetRotation_Type(RotationKind);
21367  nVertex[iMarker]++;
21368  }
21369  }
21370  }
21371 }
21372 
21374 
21375  unsigned short iMarker;
21376  unsigned long iVertex, iPoint;
21377  int iProcessor = size;
21378 
21379  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
21380  if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) {
21381  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21382  iPoint = vertex[iMarker][iVertex]->GetNode();
21383  if (node[iPoint]->GetDomain()) {
21384  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor);
21385  }
21386  }
21387  }
21388  }
21389 
21390 }
21391 
21393 
21394  unsigned short iMarker;
21395  unsigned long iVertex, iPoint;
21396  int iProcessor = size;
21397 
21398  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
21399  if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) ||
21400  (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) {
21401  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21402  iPoint = vertex[iMarker][iVertex]->GetNode();
21403  if (node[iPoint]->GetDomain()) {
21404  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor);
21405  }
21406  }
21407  }
21408  }
21409 
21410 }
21411 
21413 
21414  unsigned short iMarker;
21415  unsigned long iVertex, iPoint;
21416  int iProcessor = size;
21417 
21418  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
21419  if (config->GetMarker_All_KindBC(iMarker) == INTERFACE_BOUNDARY) {
21420  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21421  iPoint = vertex[iMarker][iVertex]->GetNode();
21422  if (node[iPoint]->GetDomain()) {
21423  vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor);
21424  }
21425  }
21426  }
21427  }
21428 
21429 }
21430 
21431 void CMultiGridGeometry::SetControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) {
21432 
21433  unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iEdge, iParent;
21434  long FineEdge, CoarseEdge;
21435  unsigned short iChildren, iNode, iDim;
21436  bool change_face_orientation;
21437  su2double *Normal, Coarse_Volume, Area, *NormalFace = NULL;
21438  Normal = new su2double [nDim];
21439 
21440  /*--- Compute the area of the coarse volume ---*/
21441  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) {
21442  node[iCoarsePoint]->SetVolume(0.0);
21443  Coarse_Volume = 0.0;
21444  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21445  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21446  Coarse_Volume += fine_grid->node[iFinePoint]->GetVolume();
21447  }
21448  node[iCoarsePoint]->SetVolume(Coarse_Volume);
21449  }
21450 
21451  /*--- Update or not the values of faces at the edge ---*/
21452  if (action != ALLOCATE) {
21453  for (iEdge=0; iEdge < nEdge; iEdge++)
21454  edge[iEdge]->SetZeroValues();
21455  }
21456 
21457  for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++)
21458  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21459  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21460 
21461  for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) {
21462  iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode);
21463  iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV();
21464  if ((iParent != iCoarsePoint) && (iParent < iCoarsePoint)) {
21465 
21466  FineEdge = fine_grid->FindEdge(iFinePoint, iFinePoint_Neighbor);
21467 
21468  change_face_orientation = false;
21469  if (iFinePoint < iFinePoint_Neighbor) change_face_orientation = true;
21470 
21471  CoarseEdge = FindEdge(iParent, iCoarsePoint);
21472 
21473  fine_grid->edge[FineEdge]->GetNormal(Normal);
21474 
21475  if (change_face_orientation) {
21476  for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim];
21477  edge[CoarseEdge]->AddNormal(Normal);
21478  }
21479  else {
21480  edge[CoarseEdge]->AddNormal(Normal);
21481  }
21482  }
21483  }
21484  }
21485  delete[] Normal;
21486 
21487  /*--- Check if there is a normal with null area ---*/
21488 
21489  for (iEdge = 0; iEdge < nEdge; iEdge++) {
21490  NormalFace = edge[iEdge]->GetNormal();
21491  Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim];
21492  Area = sqrt(Area);
21493  if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS;
21494  }
21495 
21496 }
21497 
21498 void CMultiGridGeometry::SetBoundControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) {
21499  unsigned long iCoarsePoint, iFinePoint, FineVertex, iVertex;
21500  unsigned short iMarker, iChildren, iDim;
21501  su2double *Normal, Area, *NormalFace = NULL;
21502 
21503  Normal = new su2double [nDim];
21504 
21505  if (action != ALLOCATE) {
21506  for (iMarker = 0; iMarker < nMarker; iMarker++)
21507  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++)
21508  vertex[iMarker][iVertex]->SetZeroValues();
21509  }
21510 
21511  for (iMarker = 0; iMarker < nMarker; iMarker ++)
21512  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21513  iCoarsePoint = vertex[iMarker][iVertex]->GetNode();
21514  for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) {
21515  iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren);
21516  if (fine_grid->node[iFinePoint]->GetVertex(iMarker)!=-1) {
21517  FineVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker);
21518  fine_grid->vertex[iMarker][FineVertex]->GetNormal(Normal);
21519  vertex[iMarker][iVertex]->AddNormal(Normal);
21520  }
21521  }
21522  }
21523 
21524  delete[] Normal;
21525 
21526  /*--- Check if there is a normal with null area ---*/
21527  for (iMarker = 0; iMarker < nMarker; iMarker ++)
21528  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21529  NormalFace = vertex[iMarker][iVertex]->GetNormal();
21530  Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim];
21531  Area = sqrt(Area);
21532  if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS;
21533  }
21534 
21535 }
21536 
21538  unsigned long Point_Fine, Point_Coarse;
21539  unsigned short iChildren, iDim;
21540  su2double Area_Parent, Area_Children;
21541  su2double *Coordinates_Fine, *Coordinates;
21542  Coordinates = new su2double[nDim];
21543 
21544  for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) {
21545  Area_Parent = node[Point_Coarse]->GetVolume();
21546  for (iDim = 0; iDim < nDim; iDim++) Coordinates[iDim] = 0.0;
21547  for (iChildren = 0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++) {
21548  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren);
21549  Area_Children = geometry->node[Point_Fine]->GetVolume();
21550  Coordinates_Fine = geometry->node[Point_Fine]->GetCoord();
21551  for (iDim = 0; iDim < nDim; iDim++)
21552  Coordinates[iDim] += Coordinates_Fine[iDim]*Area_Children/Area_Parent;
21553  }
21554  for (iDim = 0; iDim < nDim; iDim++)
21555  node[Point_Coarse]->SetCoord(iDim, Coordinates[iDim]);
21556  }
21557  delete[] Coordinates;
21558 }
21559 
21560 void CMultiGridGeometry::SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker){
21561 
21562  unsigned long Point_Fine, Point_Coarse, iVertex;
21563  unsigned short iChildren;
21564  long Vertex_Fine;
21565  su2double Area_Parent, Area_Children;
21566  su2double WallHeatFlux_Fine, WallHeatFlux_Coarse;
21567  bool isVertex;
21568  int numberVertexChildren;
21569 
21570  for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){
21571  Point_Coarse = vertex[val_marker][iVertex]->GetNode();
21572  if (node[Point_Coarse]->GetDomain()){
21573  Area_Parent = 0.0;
21574  WallHeatFlux_Coarse = 0.0;
21575  numberVertexChildren = 0;
21576  /*--- Compute area parent by taking into account only volumes that are on the marker ---*/
21577  for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){
21578  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren);
21579  isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1);
21580  if (isVertex){
21581  numberVertexChildren += 1;
21582  Area_Parent += geometry->node[Point_Fine]->GetVolume();
21583  }
21584  }
21585 
21586  /*--- Loop again and propagate values to the coarser level ---*/
21587  for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){
21588  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren);
21589  Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker);
21590  isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1);
21591  if(isVertex){
21592  Area_Children = geometry->node[Point_Fine]->GetVolume();
21593  //Get the customized BC values on fine level and compute the values at coarse level
21594  WallHeatFlux_Fine = geometry->GetCustomBoundaryHeatFlux(val_marker, Vertex_Fine);
21595  WallHeatFlux_Coarse += WallHeatFlux_Fine*Area_Children/Area_Parent;
21596  }
21597 
21598  }
21599  //Set the customized BC values at coarse level
21600  CustomBoundaryHeatFlux[val_marker][iVertex] = WallHeatFlux_Coarse;
21601  }
21602  }
21603 
21604 }
21605 
21606 void CMultiGridGeometry::SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker){
21607 
21608  unsigned long Point_Fine, Point_Coarse, iVertex;
21609  unsigned short iChildren;
21610  long Vertex_Fine;
21611  su2double Area_Parent, Area_Children;
21612  su2double WallTemperature_Fine, WallTemperature_Coarse;
21613  bool isVertex;
21614  int numberVertexChildren;
21615 
21616  for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){
21617  Point_Coarse = vertex[val_marker][iVertex]->GetNode();
21618  if (node[Point_Coarse]->GetDomain()){
21619  Area_Parent = 0.0;
21620  WallTemperature_Coarse = 0.0;
21621  numberVertexChildren = 0;
21622  /*--- Compute area parent by taking into account only volumes that are on the marker ---*/
21623  for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){
21624  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren);
21625  isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1);
21626  if (isVertex){
21627  numberVertexChildren += 1;
21628  Area_Parent += geometry->node[Point_Fine]->GetVolume();
21629  }
21630  }
21631 
21632  /*--- Loop again and propagate values to the coarser level ---*/
21633  for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){
21634  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren);
21635  Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker);
21636  isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1);
21637  if(isVertex){
21638  Area_Children = geometry->node[Point_Fine]->GetVolume();
21639  //Get the customized BC values on fine level and compute the values at coarse level
21640  WallTemperature_Fine = geometry->GetCustomBoundaryTemperature(val_marker, Vertex_Fine);
21641  WallTemperature_Coarse += WallTemperature_Fine*Area_Children/Area_Parent;
21642  }
21643 
21644  }
21645  //Set the customized BC values at coarse level
21646  CustomBoundaryTemperature[val_marker][iVertex] = WallTemperature_Coarse;
21647  }
21648  }
21649 
21650 }
21651 
21652 void CMultiGridGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print) {
21653 
21654  unsigned long iPoint_Coarse;
21655  su2double *RotVel, Distance[3] = {0.0,0.0,0.0}, *Coord;
21656  su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, L_Ref;
21657  RotVel = new su2double [3];
21658 
21659  /*--- Center of rotation & angular velocity vector from config. ---*/
21660 
21661  Center[0] = config->GetMotion_Origin_X(val_iZone);
21662  Center[1] = config->GetMotion_Origin_Y(val_iZone);
21663  Center[2] = config->GetMotion_Origin_Z(val_iZone);
21664  Omega[0] = config->GetRotation_Rate_X(val_iZone)/config->GetOmega_Ref();
21665  Omega[1] = config->GetRotation_Rate_Y(val_iZone)/config->GetOmega_Ref();
21666  Omega[2] = config->GetRotation_Rate_Z(val_iZone)/config->GetOmega_Ref();
21667  L_Ref = config->GetLength_Ref();
21668 
21669  /*--- Loop over all nodes and set the rotational velocity. ---*/
21670 
21671  for (iPoint_Coarse = 0; iPoint_Coarse < GetnPoint(); iPoint_Coarse++) {
21672 
21673  /*--- Get the coordinates of the current node ---*/
21674 
21675  Coord = node[iPoint_Coarse]->GetCoord();
21676 
21677  /*--- Calculate the non-dim. distance from the rotation center ---*/
21678 
21679  Distance[0] = (Coord[0]-Center[0])/L_Ref;
21680  Distance[1] = (Coord[1]-Center[1])/L_Ref;
21681  Distance[2] = (Coord[2]-Center[2])/L_Ref;
21682 
21683  /*--- Calculate the angular velocity as omega X r ---*/
21684 
21685  RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]);
21686  RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]);
21687  RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]);
21688 
21689  /*--- Store the grid velocity at this node ---*/
21690 
21691  node[iPoint_Coarse]->SetGridVel(RotVel);
21692 
21693  }
21694 
21695  delete [] RotVel;
21696 
21697 }
21698 
21700 
21701  unsigned long iPoint, iVertex;
21702  unsigned short iMarker, iMarkerShroud;
21703  su2double RotVel[3];
21704 
21705  RotVel[0] = 0.0;
21706  RotVel[1] = 0.0;
21707  RotVel[2] = 0.0;
21708 
21709  /*--- Loop over all vertex in the shroud marker and set the rotational velocity to 0.0 ---*/
21710  for (iMarker = 0; iMarker < nMarker; iMarker++){
21711  for(iMarkerShroud=0; iMarkerShroud < config->GetnMarker_Shroud(); iMarkerShroud++){
21712  if(config->GetMarker_Shroud(iMarkerShroud) == config->GetMarker_All_TagBound(iMarker)){
21713  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21714  iPoint = vertex[iMarker][iVertex]->GetNode();
21715  node[iPoint]->SetGridVel(RotVel);
21716  }
21717  }
21718  }
21719  }
21720 }
21721 
21722 void CMultiGridGeometry::SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print) {
21723 
21724  unsigned iDim;
21725  unsigned long iPoint_Coarse;
21726  su2double xDot[3] = {0.0,0.0,0.0};
21727 
21728  /*--- Get the translational velocity vector from config ---*/
21729 
21730  xDot[0] = config->GetTranslation_Rate_X(val_iZone)/config->GetVelocity_Ref();
21731  xDot[1] = config->GetTranslation_Rate_Y(val_iZone)/config->GetVelocity_Ref();
21732  xDot[2] = config->GetTranslation_Rate_Z(val_iZone)/config->GetVelocity_Ref();
21733 
21734  /*--- Loop over all nodes and set the translational velocity ---*/
21735 
21736  for (iPoint_Coarse = 0; iPoint_Coarse < nPoint; iPoint_Coarse++) {
21737 
21738  /*--- Store the grid velocity at this node ---*/
21739 
21740  for (iDim = 0; iDim < nDim; iDim++)
21741  node[iPoint_Coarse]->SetGridVel(iDim,xDot[iDim]);
21742 
21743  }
21744 
21745 }
21746 
21747 void CMultiGridGeometry::SetGridVelocity(CConfig *config, unsigned long iter) {
21748 
21749  /*--- Local variables ---*/
21750 
21751  su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL;
21752  su2double TimeStep, GridVel = 0.0;
21753  unsigned long Point_Coarse;
21754  unsigned short iDim;
21755 
21756  /*--- Compute the velocity of each node in the volume mesh ---*/
21757 
21758  for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) {
21759 
21760  /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/
21761 
21762  Coord_nM1 = node[Point_Coarse]->GetCoord_n1();
21763  Coord_n = node[Point_Coarse]->GetCoord_n();
21764  Coord_nP1 = node[Point_Coarse]->GetCoord();
21765 
21766  /*--- Unsteady time step ---*/
21767 
21768  TimeStep = config->GetDelta_UnstTimeND();
21769 
21770  /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/
21771 
21772  for (iDim = 0; iDim < nDim; iDim++) {
21773  if (config->GetUnsteady_Simulation() == DT_STEPPING_1ST)
21774  GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep;
21775  if (config->GetUnsteady_Simulation() == DT_STEPPING_2ND)
21776  GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim]
21777  + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep);
21778 
21779  /*--- Store grid velocity for this point ---*/
21780 
21781  node[Point_Coarse]->SetGridVel(iDim, GridVel);
21782 
21783  }
21784  }
21785 }
21786 
21788 
21789  /*--- Local variables ---*/
21790  unsigned short iDim, iChild;
21791  unsigned long Point_Coarse, Point_Fine;
21792  su2double Area_Parent, Area_Child, Grid_Vel[3], *Grid_Vel_Fine;
21793 
21794  /*--- Loop over all coarse mesh points ---*/
21795  for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) {
21796  Area_Parent = node[Point_Coarse]->GetVolume();
21797 
21798  /*--- Zero out the grid velocity ---*/
21799  for (iDim = 0; iDim < nDim; iDim++)
21800  Grid_Vel[iDim] = 0.0;
21801 
21802  /*--- Loop over all of the children for this coarse CV and compute
21803  a grid velocity based on the values in the child CVs (fine mesh). ---*/
21804  for (iChild = 0; iChild < node[Point_Coarse]->GetnChildren_CV(); iChild++) {
21805  Point_Fine = node[Point_Coarse]->GetChildren_CV(iChild);
21806  Area_Child = fine_mesh->node[Point_Fine]->GetVolume();
21807  Grid_Vel_Fine = fine_mesh->node[Point_Fine]->GetGridVel();
21808  for (iDim = 0; iDim < nDim; iDim++)
21809  Grid_Vel[iDim] += Grid_Vel_Fine[iDim]*Area_Child/Area_Parent;
21810  }
21811 
21812  /*--- Set the grid velocity for this coarse node. ---*/
21813  for (iDim = 0; iDim < nDim; iDim++)
21814  node[Point_Coarse]->SetGridVel(iDim, Grid_Vel[iDim]);
21815  }
21816 }
21817 
21818 
21820 
21821  unsigned short iMarker, iDim;
21822  unsigned long iPoint, iVertex;
21823 
21824  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
21825 
21826  if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE &&
21827  config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY &&
21828  config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) {
21829 
21830  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21831 
21832  iPoint = vertex[iMarker][iVertex]->GetNode();
21833 
21834  /*--- If the node belong to the domain ---*/
21835  if (node[iPoint]->GetDomain()) {
21836 
21837  /*--- Compute closest normal neighbor ---*/
21838  su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord;
21839  unsigned long Point_Normal = 0, jPoint;
21840  unsigned short iNeigh;
21841  su2double *Normal = vertex[iMarker][iVertex]->GetNormal();
21842  cos_max = -1.0;
21843  for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) {
21844  jPoint = node[iPoint]->GetPoint(iNeigh);
21845  scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0;
21846  for (iDim = 0; iDim < nDim; iDim++) {
21847  diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim);
21848  scalar_prod += diff_coord*Normal[iDim];
21849  norm_vect += diff_coord*diff_coord;
21850  norm_Normal += Normal[iDim]*Normal[iDim];
21851  }
21852  norm_vect = sqrt(norm_vect);
21853  norm_Normal = sqrt(norm_Normal);
21854  cos_alpha = scalar_prod/(norm_vect*norm_Normal);
21855 
21856  /*--- Get maximum cosine (not minimum because normals are oriented inwards) ---*/
21857  if (cos_alpha >= cos_max) {
21858  Point_Normal = jPoint;
21859  cos_max = cos_alpha;
21860  }
21861  }
21862  vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal);
21863  }
21864  }
21865  }
21866  }
21867 }
21868 
21869 
21871  bool loop_on;
21872  unsigned short iMarker = 0;
21873  su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL;
21874  unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0;
21875 
21876  /*--- Compute the total number of points on the near-field ---*/
21877  nVertex_Wall = 0;
21878  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
21879  if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) ||
21880  (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ||
21881  (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ||
21882  (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION))
21883  nVertex_Wall += nVertex[iMarker];
21884 
21885 
21886  /*--- Create an array with all the coordinates, points, pressures, face area,
21887  equivalent area, and nearfield weight ---*/
21888  Xcoord = new su2double[nVertex_Wall];
21889  Ycoord = new su2double[nVertex_Wall];
21890  if (nDim == 3) Zcoord = new su2double[nVertex_Wall];
21891  FaceArea = new su2double[nVertex_Wall];
21892 
21893  /*--- Copy the boundary information to an array ---*/
21894  iVertex_Wall = 0;
21895  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
21896  if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) ||
21897  (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) ||
21898  (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ||
21899  (config->GetMarker_All_KindBC(iMarker) == TRANSPIRATION))
21900  for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) {
21901  iPoint = vertex[iMarker][iVertex]->GetNode();
21902  Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0);
21903  Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1);
21904  if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2);
21905  Face_Normal = vertex[iMarker][iVertex]->GetNormal();
21906  FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]);
21907  iVertex_Wall ++;
21908  }
21909 
21910 
21911  //vector<su2double> XCoordList;
21912  vector<su2double>::iterator IterXCoordList;
21913 
21914  for (iVertex = 0; iVertex < nVertex_Wall; iVertex++)
21915  XCoordList.push_back(Xcoord[iVertex]);
21916 
21917  sort( XCoordList.begin(), XCoordList.end());
21918  IterXCoordList = unique( XCoordList.begin(), XCoordList.end());
21919  XCoordList.resize( IterXCoordList - XCoordList.begin() );
21920 
21921  /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/
21922  Xcoord_plane.resize(XCoordList.size());
21923  Ycoord_plane.resize(XCoordList.size());
21924  if (nDim==3) Zcoord_plane.resize(XCoordList.size());
21925  FaceArea_plane.resize(XCoordList.size());
21926  Plane_points.resize(XCoordList.size());
21927 
21928 
21929  su2double dist_ratio;
21930  unsigned long iCoord;
21931 
21932  /*--- Distribute the values among the different PhiAngles ---*/
21933  for (iPoint = 0; iPoint < nPoint; iPoint++) {
21934  if (node[iPoint]->GetDomain()) {
21935  loop_on = true;
21936  for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) {
21937  dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]);
21938  if (dist_ratio >= 0 && dist_ratio <= 1.0) {
21939  if (dist_ratio <= 0.5) iCoord = ixCoord;
21940  else iCoord = ixCoord+1;
21941  Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) );
21942  Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) );
21943  if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) );
21944  FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume());
21945  Plane_points[iCoord].push_back(iPoint );
21946  loop_on = false;
21947  }
21948  }
21949  }
21950  }
21951 
21952  unsigned long auxPoint;
21953  /*--- Order the arrays in ascending values of y ---*/
21954  for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++)
21955  for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++)
21956  for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++)
21957  if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) {
21958  auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord;
21959  auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord;
21960  auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint;
21961  if (nDim==3) {
21962  auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord;
21963  }
21964  auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea;
21965  }
21966 
21967  /*--- Delete structures ---*/
21968  delete[] Xcoord; delete[] Ycoord;
21969  if (Zcoord != NULL) delete[] Zcoord;
21970  delete[] FaceArea;
21971 }
21972 
21974  unsigned long nElem_new, nPoint_new, jPoint, iPoint, iElem, jElem, iVertex,
21976  nelem_pyramid = 0, iIndex, newElementsBound = 0;
21977  unsigned short iMarker, nPeriodic = 0, iPeriodic;
21978  su2double *center, *angles, rotMatrix[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}},
21979  translation[3], *trans, theta, phi, psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi,
21980  dx, dy, dz, rotCoord[3], *Coord_i;
21981  unsigned short nMarker_Max = config->GetnMarker_Max();
21982 
21983  /*--- We only create the mirror structure for the second boundary ---*/
21984  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) {
21985  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) {
21986  /*--- Evaluate the number of periodic boundary conditions ---*/
21987  nPeriodic++;
21988  }
21989  }
21990  bool *CreateMirror = new bool[nPeriodic+1];
21991  CreateMirror[0] = false;
21992  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
21993  if (iPeriodic <= nPeriodic/2) CreateMirror[iPeriodic] = false;
21994  else CreateMirror[iPeriodic] = true;
21995  }
21996 
21997  /*--- Write the number of dimensions of the problem ---*/
21998  nDim = geometry->GetnDim();
21999 
22000  /*--- Copy the new boundary element information from the geometry class.
22001  Be careful, as these are pointers to vectors/objects. ---*/
22002  nNewElem_BoundPer = geometry->nNewElem_Bound;
22003  newBoundPer = geometry->newBound;
22004 
22005  /*--- Count the number of new boundary elements. ---*/
22006  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
22007  newElementsBound += nNewElem_BoundPer[iMarker];
22008 
22009  /*--- Loop over the original grid to perform the dimensionalizaton of the new vectors ---*/
22010  nElem_new = 0; nPoint_new = 0;
22011  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22012  if (CreateMirror[iPeriodic]) {
22013  nElem_new += geometry->PeriodicElem[iPeriodic].size();
22014  nPoint_new += geometry->PeriodicPoint[iPeriodic][0].size();
22015  }
22016  }
22017 
22018  cout << "Number of new points: " << nPoint_new << "." << endl;
22019  cout << "Number of new interior elements: " << nElem_new << "." << endl;
22020  cout << "Number of new boundary elements added to preexisting markers: " << newElementsBound << "." << endl;
22021 
22022  /*--- Create a copy of the original grid ---*/
22023  elem = new CPrimalGrid*[geometry->GetnElem() + nElem_new];
22024  for (iElem = 0; iElem < geometry->GetnElem(); iElem ++) {
22025  switch(geometry->elem[iElem]->GetVTK_Type()) {
22026  case TRIANGLE:
22027  elem[iElem] = new CTriangle(geometry->elem[iElem]->GetNode(0),
22028  geometry->elem[iElem]->GetNode(1),
22029  geometry->elem[iElem]->GetNode(2), 2);
22030  nelem_triangle++;
22031  break;
22032 
22033  case QUADRILATERAL:
22034  elem[iElem] = new CQuadrilateral(geometry->elem[iElem]->GetNode(0),
22035  geometry->elem[iElem]->GetNode(1),
22036  geometry->elem[iElem]->GetNode(2),
22037  geometry->elem[iElem]->GetNode(3), 2);
22038  nelem_quad++;
22039  break;
22040 
22041  case TETRAHEDRON:
22042  elem[iElem] = new CTetrahedron(geometry->elem[iElem]->GetNode(0),
22043  geometry->elem[iElem]->GetNode(1),
22044  geometry->elem[iElem]->GetNode(2),
22045  geometry->elem[iElem]->GetNode(3));
22046  nelem_tetra++;
22047  break;
22048 
22049  case HEXAHEDRON:
22050  elem[iElem] = new CHexahedron(geometry->elem[iElem]->GetNode(0),
22051  geometry->elem[iElem]->GetNode(1),
22052  geometry->elem[iElem]->GetNode(2),
22053  geometry->elem[iElem]->GetNode(3),
22054  geometry->elem[iElem]->GetNode(4),
22055  geometry->elem[iElem]->GetNode(5),
22056  geometry->elem[iElem]->GetNode(6),
22057  geometry->elem[iElem]->GetNode(7));
22058  nelem_hexa++;
22059  break;
22060 
22061  case PRISM:
22062  elem[iElem] = new CPrism(geometry->elem[iElem]->GetNode(0),
22063  geometry->elem[iElem]->GetNode(1),
22064  geometry->elem[iElem]->GetNode(2),
22065  geometry->elem[iElem]->GetNode(3),
22066  geometry->elem[iElem]->GetNode(4),
22067  geometry->elem[iElem]->GetNode(5));
22068  nelem_prism++;
22069  break;
22070 
22071  case PYRAMID:
22072  elem[iElem] = new CPyramid(geometry->elem[iElem]->GetNode(0),
22073  geometry->elem[iElem]->GetNode(1),
22074  geometry->elem[iElem]->GetNode(2),
22075  geometry->elem[iElem]->GetNode(3),
22076  geometry->elem[iElem]->GetNode(4));
22077  nelem_pyramid++;
22078  break;
22079 
22080  }
22081  }
22082 
22083  /*--- Create a list with all the points and the new index ---*/
22084  unsigned long *Index = new unsigned long [geometry->GetnPoint()];
22085  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) Index[iPoint] = 0;
22086 
22087  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22088  if (CreateMirror[iPeriodic]) {
22089  for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) {
22090  iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex];
22091  Index[iPoint] = geometry->PeriodicPoint[iPeriodic][1][iIndex];
22092  }
22093  }
22094  }
22095 
22096  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++)
22097  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY)
22098  for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); iVertex++) {
22099  iPoint = geometry->vertex[iMarker][iVertex]->GetNode();
22100  jPoint = geometry->vertex[iMarker][iVertex]->GetDonorPoint();
22101  Index[iPoint] = jPoint;
22102  }
22103 
22104  /*--- Add the new elements due to the periodic boundary condtion ---*/
22105  iElem = geometry->GetnElem();
22106 
22107  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22108  if (CreateMirror[iPeriodic]) {
22109  for (iIndex = 0; iIndex < geometry->PeriodicElem[iPeriodic].size(); iIndex++) {
22110  jElem = geometry->PeriodicElem[iPeriodic][iIndex];
22111 
22112  switch(geometry->elem[jElem]->GetVTK_Type()) {
22113  case TRIANGLE:
22114  elem[iElem] = new CTriangle(Index[geometry->elem[jElem]->GetNode(0)],
22115  Index[geometry->elem[jElem]->GetNode(1)],
22116  Index[geometry->elem[jElem]->GetNode(2)], 2);
22117  iElem++; nelem_triangle++;
22118  break;
22119 
22120  case QUADRILATERAL:
22121  elem[iElem] = new CQuadrilateral(Index[geometry->elem[jElem]->GetNode(0)],
22122  Index[geometry->elem[jElem]->GetNode(1)],
22123  Index[geometry->elem[jElem]->GetNode(2)],
22124  Index[geometry->elem[jElem]->GetNode(3)], 2);
22125  iElem++; nelem_quad++;
22126  break;
22127 
22128  case TETRAHEDRON:
22129  elem[iElem] = new CTetrahedron(Index[geometry->elem[jElem]->GetNode(0)],
22130  Index[geometry->elem[jElem]->GetNode(1)],
22131  Index[geometry->elem[jElem]->GetNode(2)],
22132  Index[geometry->elem[jElem]->GetNode(3)]);
22133  iElem++; nelem_tetra++;
22134  break;
22135 
22136  case HEXAHEDRON:
22137  elem[iElem] = new CHexahedron(Index[geometry->elem[jElem]->GetNode(0)],
22138  Index[geometry->elem[jElem]->GetNode(1)],
22139  Index[geometry->elem[jElem]->GetNode(2)],
22140  Index[geometry->elem[jElem]->GetNode(3)],
22141  Index[geometry->elem[jElem]->GetNode(4)],
22142  Index[geometry->elem[jElem]->GetNode(5)],
22143  Index[geometry->elem[jElem]->GetNode(6)],
22144  Index[geometry->elem[jElem]->GetNode(7)]);
22145  iElem++; nelem_hexa++;
22146  break;
22147 
22148  case PRISM:
22149  elem[iElem] = new CPrism(Index[geometry->elem[jElem]->GetNode(0)],
22150  Index[geometry->elem[jElem]->GetNode(1)],
22151  Index[geometry->elem[jElem]->GetNode(2)],
22152  Index[geometry->elem[jElem]->GetNode(3)],
22153  Index[geometry->elem[jElem]->GetNode(4)],
22154  Index[geometry->elem[jElem]->GetNode(5)]);
22155  iElem++; nelem_prism++;
22156  break;
22157 
22158  case PYRAMID:
22159  elem[iElem] = new CPyramid(Index[geometry->elem[jElem]->GetNode(0)],
22160  Index[geometry->elem[jElem]->GetNode(1)],
22161  Index[geometry->elem[jElem]->GetNode(2)],
22162  Index[geometry->elem[jElem]->GetNode(3)],
22163  Index[geometry->elem[jElem]->GetNode(4)]);
22164  iElem++; nelem_pyramid++;
22165  break;
22166 
22167  }
22168  }
22169  }
22170  }
22171 
22172  nElem = geometry->GetnElem() + nElem_new;
22173 
22174  /*--- Add the old points ---*/
22175 
22176  nPointNode = geometry->GetnPoint() + nPoint_new;
22177  node = new CPoint*[geometry->GetnPoint() + nPoint_new];
22178  for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint ++) {
22179  if (geometry->GetnDim() == 2)
22180  node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0),
22181  geometry->node[iPoint]->GetCoord(1), iPoint, config);
22182  if (geometry->GetnDim() == 3)
22183  node[iPoint] = new CPoint(geometry->node[iPoint]->GetCoord(0),
22184  geometry->node[iPoint]->GetCoord(1),
22185  geometry->node[iPoint]->GetCoord(2), iPoint, config);
22186  }
22187 
22188  /*--- Add the new points due to the periodic boundary condtion (only in the mirror part) ---*/
22189  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22190  if (CreateMirror[iPeriodic]) {
22191  for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) {
22192 
22193  /*--- From iPeriodic obtain the iMarker ---*/
22194  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++)
22195  if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break;
22196 
22197  /*--- Retrieve the supplied periodic information. ---*/
22198  center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker));
22199  angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker));
22200  trans = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker));
22201 
22202  /*--- Store center - trans as it is constant and will be added on.
22203  Note the subtraction, as this is the inverse translation. ---*/
22204  translation[0] = center[0] - trans[0];
22205  translation[1] = center[1] - trans[1];
22206  translation[2] = center[2] - trans[2];
22207 
22208  /*--- Store angles separately for clarity. Compute sines/cosines.
22209  Note the negative sign, as this is the inverse rotation. ---*/
22210  theta = -angles[0];
22211  phi = -angles[1];
22212  psi = -angles[2];
22213 
22214  cosTheta = cos(theta); cosPhi = cos(phi); cosPsi = cos(psi);
22215  sinTheta = sin(theta); sinPhi = sin(phi); sinPsi = sin(psi);
22216 
22217  /*--- Compute the rotation matrix. Note that the implicit
22218  ordering is rotation about the x-axis, y-axis, then z-axis. ---*/
22219  rotMatrix[0][0] = cosPhi*cosPsi;
22220  rotMatrix[1][0] = cosPhi*sinPsi;
22221  rotMatrix[2][0] = -sinPhi;
22222 
22223  rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi;
22224  rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi;
22225  rotMatrix[2][1] = sinTheta*cosPhi;
22226 
22227  rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi;
22228  rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi;
22229  rotMatrix[2][2] = cosTheta*cosPhi;
22230 
22231  /*--- Retrieve node information for this boundary point. ---*/
22232  iPoint = geometry->PeriodicPoint[iPeriodic][0][iIndex];
22233  jPoint = geometry->PeriodicPoint[iPeriodic][1][iIndex];
22234  Coord_i = geometry->node[iPoint]->GetCoord();
22235 
22236  /*--- Get the position vector from rot center to point. ---*/
22237  dx = Coord_i[0] - center[0];
22238  dy = Coord_i[1] - center[1];
22239  if (nDim == 3) {
22240  dz = Coord_i[2] - center[2];
22241  } else {
22242  dz = 0.0;
22243  }
22244 
22245  /*--- Compute transformed point coordinates. ---*/
22246  rotCoord[0] = rotMatrix[0][0]*dx + rotMatrix[0][1]*dy + rotMatrix[0][2]*dz + translation[0];
22247  rotCoord[1] = rotMatrix[1][0]*dx + rotMatrix[1][1]*dy + rotMatrix[1][2]*dz + translation[1];
22248  rotCoord[2] = rotMatrix[2][0]*dx + rotMatrix[2][1]*dy + rotMatrix[2][2]*dz + translation[2];
22249 
22250  /*--- Save the new points with the new coordinates. ---*/
22251  if (geometry->GetnDim() == 2)
22252  node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], jPoint, config);
22253  if (geometry->GetnDim() == 3)
22254  node[jPoint] = new CPoint(rotCoord[0], rotCoord[1], rotCoord[2], jPoint, config);
22255 
22256  }
22257  }
22258  }
22259 
22260  nPoint = geometry->GetnPoint() + nPoint_new;
22261 
22262  /*--- Add the old boundary, reserving space for two new bc (send/recive periodic bc) ---*/
22263  nMarker = geometry->GetnMarker() + 2;
22264  nElem_Bound = new unsigned long [nMarker];
22265  bound = new CPrimalGrid**[nMarker];
22266  Tag_to_Marker = new string [nMarker_Max];
22267  config->SetnMarker_All(nMarker);
22268 
22269  /*--- Copy the olf boundary ---*/
22270  for (iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) {
22271 
22272  bound[iMarker] = new CPrimalGrid* [geometry->GetnElem_Bound(iMarker)];
22273 
22274  for (iVertex = 0; iVertex < geometry->GetnElem_Bound(iMarker); iVertex++) {
22275  if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == LINE)
22276  bound[iMarker][iVertex] = new CLine(geometry->bound[iMarker][iVertex]->GetNode(0),
22277  geometry->bound[iMarker][iVertex]->GetNode(1), 2);
22278  if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == TRIANGLE)
22279  bound[iMarker][iVertex] = new CTriangle(geometry->bound[iMarker][iVertex]->GetNode(0),
22280  geometry->bound[iMarker][iVertex]->GetNode(1),
22281  geometry->bound[iMarker][iVertex]->GetNode(2), 3);
22282  if (geometry->bound[iMarker][iVertex]->GetVTK_Type() == QUADRILATERAL)
22283  bound[iMarker][iVertex] = new CQuadrilateral(geometry->bound[iMarker][iVertex]->GetNode(0),
22284  geometry->bound[iMarker][iVertex]->GetNode(1),
22285  geometry->bound[iMarker][iVertex]->GetNode(2),
22286  geometry->bound[iMarker][iVertex]->GetNode(3), 3);
22287  }
22288 
22289  nElem_Bound[iMarker] = geometry->GetnElem_Bound(iMarker);
22290  Tag_to_Marker[iMarker] = geometry->GetMarker_Tag(iMarker);
22291 
22292  }
22293 
22294  delete [] Index;
22295  delete [] CreateMirror;
22296 
22297 }
22298 
22300  unsigned long iElem_Bound;
22301  unsigned short iMarker;
22302 
22303  for (iMarker = 0; iMarker < nMarker; iMarker++) {
22304  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
22305  if (newBoundPer[iMarker][iElem_Bound] != NULL) delete [] newBoundPer[iMarker][iElem_Bound];
22306  }
22307  }
22308  if (newBoundPer != NULL) delete[] newBoundPer;
22309 
22310  if (nNewElem_BoundPer != NULL) delete[] nNewElem_BoundPer;
22311 
22312 }
22313 
22315  unsigned short iMarker, iPeriodic, nPeriodic = 0, iMarkerSend, iMarkerReceive;
22316  unsigned long iVertex, Counter_Send = 0, Counter_Receive = 0, iIndex;
22317 
22318  /*--- Compute the number of periodic bc on the geometry ---*/
22319  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
22320  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY)
22321  nPeriodic++;
22322 
22323  /*--- First compute the Send/Receive boundaries, count the number of points ---*/
22324  Counter_Send = 0; Counter_Receive = 0;
22325  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22326  if (geometry->PeriodicPoint[iPeriodic][0].size() != 0)
22327  Counter_Send += geometry->PeriodicPoint[iPeriodic][0].size();
22328  if (geometry->PeriodicPoint[iPeriodic][1].size() != 0)
22329  Counter_Receive += geometry->PeriodicPoint[iPeriodic][1].size();
22330  }
22331 
22332  /*--- Adimensionalization of the new boundaries ---*/
22333  iMarkerSend = nMarker - 2; iMarkerReceive = nMarker - 1;
22334  config->SetMarker_All_SendRecv(iMarkerSend,1);
22335  config->SetMarker_All_SendRecv(iMarkerReceive,-1);
22336  nElem_Bound[iMarkerSend] = Counter_Send;
22337  nElem_Bound[iMarkerReceive] = Counter_Receive;
22338  bound[iMarkerSend] = new CPrimalGrid* [Counter_Send];
22339  bound[iMarkerReceive] = new CPrimalGrid* [Counter_Receive];
22340 
22341  /*--- First we do the send ---*/
22342  iVertex = 0;
22343  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++)
22344  if (geometry->PeriodicPoint[iPeriodic][0].size() != 0)
22345  for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][0].size(); iIndex++) {
22346  bound[iMarkerSend][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][0][iIndex], nDim);
22347  bound[iMarkerSend][iVertex]->SetRotation_Type(iPeriodic);
22348  iVertex++;
22349  }
22350 
22351  /*--- Second we do the receive ---*/
22352  iVertex = 0;
22353  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++)
22354  if (geometry->PeriodicPoint[iPeriodic][1].size() != 0)
22355  for (iIndex = 0; iIndex < geometry->PeriodicPoint[iPeriodic][1].size(); iIndex++) {
22356  bound[iMarkerReceive][iVertex] = new CVertexMPI(geometry->PeriodicPoint[iPeriodic][1][iIndex], nDim);
22357  bound[iMarkerReceive][iVertex]->SetRotation_Type(iPeriodic);
22358  iVertex++;
22359  }
22360 
22361 }
22362 
22363 void CPeriodicGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) {
22364  unsigned long iElem, iPoint, iElem_Bound, GhostPoints;
22365  unsigned short iMarker, iNodes, iDim;
22366  unsigned short iMarkerReceive, iPeriodic, nPeriodic = 0;
22367  ofstream output_file;
22368  string Grid_Marker;
22369  char *cstr;
22370  su2double *center, *angles, *transl;
22371 
22372  cstr = new char [val_mesh_out_filename.size()+1];
22373  strcpy (cstr, val_mesh_out_filename.c_str());
22374 
22375  /*--- Open .su2 grid file ---*/
22376  output_file.precision(15);
22377  output_file.open(cstr, ios::out);
22378 
22379  /*--- Ghost points, look at the nodes in the send receive ---*/
22380  iMarkerReceive = nMarker - 1;
22381  GhostPoints = nElem_Bound[iMarkerReceive];
22382 
22383  /*--- Change the numbering to guarantee that the all the receive
22384  points are at the end of the file. ---*/
22385  std::vector<unsigned long> receive_nodes;
22386  std::vector<unsigned long> send_nodes;
22387  for (iMarker = 0; iMarker < nMarker; iMarker++) {
22388  if (bound[iMarker][0]->GetVTK_Type() == VERTEX) {
22389  if (config->GetMarker_All_SendRecv(iMarker) < 0) {
22390  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
22391  if (bound[iMarker][iElem_Bound]->GetRotation_Type() == 1) {
22392  receive_nodes.push_back(bound[iMarker][iElem_Bound]->GetNode(0));
22393  } else {
22394  send_nodes.push_back(bound[iMarker][iElem_Bound]->GetNode(0));
22395  }
22396  }
22397  }
22398  }
22399  }
22400 
22401  /*--- Build the sorted lists of node numbers with receive/send at the end
22402  * NewSort[i] = j maps the new number (i) to the old number (j)
22403  * ReverseSort[j] = i maps the old number (j) to the new number (i) ---*/
22404  std::vector<unsigned long> NewSort;
22405  std::vector<unsigned long> ReverseSort;
22406  for (iPoint = 0; iPoint < nPoint; iPoint++) {
22407  bool isReceive = (find(receive_nodes.begin(), receive_nodes.end(), iPoint)
22408  != receive_nodes.end());
22409  bool isSend = (find(send_nodes.begin(), send_nodes.end(), iPoint)
22410  != send_nodes.end());
22411  if (!isSend && !isReceive) {
22412  NewSort.push_back(iPoint);
22413  }
22414  }
22415  NewSort.insert(NewSort.end(), receive_nodes.begin(), receive_nodes.end());
22416  NewSort.insert(NewSort.end(), send_nodes.begin(), send_nodes.end());
22417 
22418  ReverseSort.resize(NewSort.size());
22419  for (iPoint = 0; iPoint < nPoint; iPoint++) {
22420  unsigned long jPoint;
22421  for (jPoint = 0; jPoint < nPoint; jPoint++) {
22422  if (NewSort[iPoint] == jPoint) {
22423  ReverseSort[jPoint] = iPoint;
22424  break;
22425  }
22426  }
22427  if (jPoint == nPoint) { // Loop fell through without break
22428  SU2_MPI::Error("Remapping of periodic nodes failed.", CURRENT_FUNCTION);
22429  }
22430  }
22431 
22432  /*--- Write dimension, number of elements and number of points ---*/
22433  output_file << "NDIME= " << nDim << endl;
22434  output_file << "NELEM= " << nElem << endl;
22435  for (iElem = 0; iElem < nElem; iElem++) {
22436  output_file << elem[iElem]->GetVTK_Type();
22437  for (iNodes = 0; iNodes < elem[iElem]->GetnNodes(); iNodes++)
22438  output_file << "\t" << ReverseSort[elem[iElem]->GetNode(iNodes)];
22439  output_file << "\t"<<iElem<< endl;
22440  }
22441 
22442  output_file << "NPOIN= " << nPoint << "\t" << nPoint - GhostPoints << endl;
22443  for (iPoint = 0; iPoint < nPoint; iPoint++) {
22444  for (iDim = 0; iDim < nDim; iDim++) {
22445  output_file << scientific;
22446  output_file << "\t" << node[NewSort[iPoint]]->GetCoord(iDim) ;
22447  }
22448  output_file << "\t" << iPoint << endl;
22449  }
22450 
22451  output_file << "NMARK= " << nMarker << endl;
22452  for (iMarker = 0; iMarker < nMarker; iMarker++) {
22453  if (bound[iMarker][0]->GetVTK_Type() != VERTEX) {
22454 
22455  Grid_Marker = config->GetMarker_All_TagBound(iMarker);
22456  output_file << "MARKER_TAG= " << Grid_Marker << endl;
22457  output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker] + nNewElem_BoundPer[iMarker] << endl;
22458 
22459  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
22460  output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
22461  for (iNodes = 0; iNodes < bound[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++)
22462  output_file << ReverseSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ;
22463  iNodes = bound[iMarker][iElem_Bound]->GetnNodes()-1;
22464  output_file << ReverseSort[bound[iMarker][iElem_Bound]->GetNode(iNodes)] << endl;
22465  }
22466 
22467  /*--- Write any new elements at the end of the list. ---*/
22468  if (nNewElem_BoundPer[iMarker] > 0) {
22469  for (iElem_Bound = 0; iElem_Bound < nNewElem_BoundPer[iMarker]; iElem_Bound++) {
22470  output_file << newBoundPer[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ;
22471  for (iNodes = 0; iNodes < newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1; iNodes++)
22472  output_file << ReverseSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << "\t" ;
22473  iNodes = newBoundPer[iMarker][iElem_Bound]->GetnNodes()-1;
22474  output_file << ReverseSort[newBoundPer[iMarker][iElem_Bound]->GetNode(iNodes)] << endl;
22475  }
22476  }
22477 
22478  }
22479 
22480  if (bound[iMarker][0]->GetVTK_Type() == VERTEX) {
22481  output_file << "MARKER_TAG= SEND_RECEIVE" << endl;
22482  output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl;
22483  if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl;
22484  if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl;
22485 
22486  for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) {
22487  output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" <<
22488  ReverseSort[bound[iMarker][iElem_Bound]->GetNode(0)] << "\t" <<
22489  bound[iMarker][iElem_Bound]->GetRotation_Type() << endl;
22490  }
22491  }
22492  }
22493 
22494  /*--- Compute the number of periodic bc on the geometry ---*/
22495  for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++)
22496  if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY)
22497  nPeriodic++;
22498 
22499  output_file << "NPERIODIC= " << nPeriodic + 1 << endl;
22500 
22501  /*--- Periodic 0 correspond with no movement of the surface ---*/
22502  output_file << "PERIODIC_INDEX= 0" << endl;
22503  output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl;
22504  output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl;
22505  output_file << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << "\t" << "0.000000000000000e+00" << endl;
22506 
22507  /*--- From iPeriodic obtain the iMarker ---*/
22508  for (iPeriodic = 1; iPeriodic <= nPeriodic; iPeriodic++) {
22509  for (iMarker = 0; iMarker < nMarker; iMarker++)
22510  if (iPeriodic == config->GetMarker_All_PerBound(iMarker)) break;
22511 
22512  /*--- Retrieve the supplied periodic information. ---*/
22513  center = config->GetPeriodicRotCenter(config->GetMarker_All_TagBound(iMarker));
22514  angles = config->GetPeriodicRotAngles(config->GetMarker_All_TagBound(iMarker));
22515  transl = config->GetPeriodicTranslation(config->GetMarker_All_TagBound(iMarker));
22516 
22517  output_file << "PERIODIC_INDEX= " << iPeriodic << endl;
22518  output_file << center[0] << "\t" << center[1] << "\t" << center[2] << endl;
22519  output_file << angles[0] << "\t" << angles[1] << "\t" << angles[2] << endl;
22520  output_file << transl[0] << "\t" << transl[1] << "\t" << transl[2] << endl;
22521 
22522  }
22523 
22524 
22525  output_file.close();
22526 }
22527 
22528 void CPeriodicGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) {
22529 
22530  unsigned long iElem, iPoint;
22531  unsigned short iDim;
22532  ofstream Tecplot_File;
22533 
22534  Tecplot_File.open(mesh_filename, ios::out);
22535  Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl;
22536 
22537  if (nDim == 2) {
22538  Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl;
22539  Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEQUADRILATERAL"<< endl;
22540  }
22541  if (nDim == 3) {
22542  Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl;
22543  Tecplot_File << "ZONE NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl;
22544  }
22545 
22546  for (iPoint = 0; iPoint < nPoint; iPoint++) {
22547  for (iDim = 0; iDim < nDim; iDim++)
22548  Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t";
22549  Tecplot_File << "\n";
22550  }
22551 
22552  for (iElem = 0; iElem < nElem; iElem++) {
22553  if (elem[iElem]->GetVTK_Type() == TRIANGLE) {
22554  Tecplot_File <<
22555  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22556  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 << endl;
22557  }
22558  if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) {
22559  Tecplot_File <<
22560  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22561  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl;
22562  }
22563  if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) {
22564  Tecplot_File <<
22565  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22566  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<<
22567  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
22568  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(3)+1 << endl;
22569  }
22570  if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) {
22571  Tecplot_File <<
22572  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22573  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
22574  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 <<" "<<
22575  elem[iElem]->GetNode(6)+1 <<" "<< elem[iElem]->GetNode(7)+1 << endl;
22576  }
22577  if (elem[iElem]->GetVTK_Type() == PYRAMID) {
22578  Tecplot_File <<
22579  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22580  elem[iElem]->GetNode(2)+1 <<" "<< elem[iElem]->GetNode(3)+1 <<" "<<
22581  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<<
22582  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(4)+1 << endl;
22583  }
22584  if (elem[iElem]->GetVTK_Type() == PRISM) {
22585  Tecplot_File <<
22586  elem[iElem]->GetNode(0)+1 <<" "<< elem[iElem]->GetNode(1)+1 <<" "<<
22587  elem[iElem]->GetNode(1)+1 <<" "<< elem[iElem]->GetNode(2)+1 <<" "<<
22588  elem[iElem]->GetNode(3)+1 <<" "<< elem[iElem]->GetNode(4)+1 <<" "<<
22589  elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl;
22590  }
22591  }
22592 
22593  Tecplot_File.close();
22594 }
22595 
22596 CMultiGridQueue::CMultiGridQueue(unsigned long val_npoint) {
22597  unsigned long iPoint;
22598 
22599  nPoint = val_npoint;
22600  Priority = new short[nPoint];
22601  RightCV = new bool[nPoint];
22602 
22603  QueueCV.resize(1);
22604 
22605  /*--- Queue initialization with all the points in the finer grid ---*/
22606  for (iPoint = 0; iPoint < nPoint; iPoint ++) {
22607  QueueCV[0].push_back(iPoint);
22608  Priority[iPoint] = 0;
22609  RightCV[iPoint] = true;
22610  }
22611 
22612 }
22613 
22615 
22616  delete[] Priority;
22617  delete[] RightCV;
22618 
22619 }
22620 
22621 void CMultiGridQueue::AddCV(unsigned long val_new_point, unsigned short val_number_neighbors) {
22622 
22623  unsigned short Max_Neighbors = QueueCV.size()-1;
22624 
22625  /*--- Basic check ---*/
22626  if (val_new_point > nPoint) {
22627  SU2_MPI::Error("The index of the CV is greater than the size of the priority list.", CURRENT_FUNCTION);
22628  }
22629 
22630  /*--- Resize the list ---*/
22631  if (val_number_neighbors > Max_Neighbors)
22632  QueueCV.resize(val_number_neighbors+1);
22633 
22634  /*--- Find the point in the queue ---*/
22635  bool InQueue = false;
22636  if (Priority[val_new_point] == val_number_neighbors) InQueue = true;
22637 
22638  if (!InQueue) {
22639  /*--- Add the control volume, and update the priority list ---*/
22640  QueueCV[val_number_neighbors].push_back(val_new_point);
22641  Priority[val_new_point] = val_number_neighbors;
22642  }
22643 
22644 }
22645 
22646 void CMultiGridQueue::RemoveCV(unsigned long val_remove_point) {
22647  unsigned short iPoint;
22648  bool check;
22649 
22650  /*--- Basic check ---*/
22651  if (val_remove_point > nPoint) {
22652  SU2_MPI::Error("The index of the CV is greater than the size of the priority list." , CURRENT_FUNCTION);
22653  }
22654 
22655  /*--- Find priority of the Control Volume ---*/
22656  short Number_Neighbors = Priority[val_remove_point];
22657  if (Number_Neighbors == -1) {
22658  char buf[200];
22659  SPRINTF(buf, "The CV %lu is not in the priority list.", val_remove_point);
22660  SU2_MPI::Error(string(buf), CURRENT_FUNCTION);
22661  }
22662 
22663  /*--- Find the point in the queue ---*/
22664  vector<unsigned long>::iterator ItQueue = find(QueueCV[Number_Neighbors].begin(),
22665  QueueCV[Number_Neighbors].end(),
22666  val_remove_point);
22667  if ( ItQueue != QueueCV[Number_Neighbors].end() ) QueueCV[Number_Neighbors].erase(ItQueue);
22668 
22669  Priority[val_remove_point] = -1;
22670 
22671  /*--- Check that the size of the queue is the right one ---*/
22672  unsigned short Size_QueueCV = 0;
22673  check = false;
22674  for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++)
22675  if (QueueCV[iPoint].size() != 0) { Size_QueueCV = iPoint; check = true;}
22676 
22677  /*--- Resize the queue, if check = false, the queue is empty, at least
22678  we need one element in the queue ---*/
22679  if (check) QueueCV.resize(Size_QueueCV+1);
22680  else QueueCV.resize(1);
22681 
22682 }
22683 
22684 void CMultiGridQueue::MoveCV(unsigned long val_move_point, short val_number_neighbors) {
22685 
22686  if (val_number_neighbors < 0) {
22687  val_number_neighbors = 0;
22688  RightCV[val_move_point] = false;
22689  }
22690  else {
22691  RightCV[val_move_point] = true;
22692  }
22693 
22694  /*--- Remove the control volume ---*/
22695  RemoveCV(val_move_point);
22696 
22697  /*--- Add a new control volume ---*/
22698  AddCV(val_move_point, val_number_neighbors);
22699 
22700 }
22701 
22702 void CMultiGridQueue::IncrPriorityCV(unsigned long val_incr_point) {
22703 
22704  /*--- Find the priority list ---*/
22705  short Number_Neighbors = Priority[val_incr_point];
22706  if (Number_Neighbors == -1) {
22707  char buf[200];
22708  SPRINTF(buf, "The CV %lu is not in the priority list.", val_incr_point);
22709  SU2_MPI::Error(string(buf), CURRENT_FUNCTION);
22710  }
22711 
22712  /*--- Remove the control volume ---*/
22713  RemoveCV(val_incr_point);
22714 
22715  /*--- Increase the priority ---*/
22716  AddCV(val_incr_point, Number_Neighbors+1);
22717 
22718 }
22719 
22720 void CMultiGridQueue::RedPriorityCV(unsigned long val_red_point) {
22721 
22722  /*--- Find the priority list ---*/
22723  short Number_Neighbors = Priority[val_red_point];
22724  if (Number_Neighbors == -1) {
22725  char buf[200];
22726  SPRINTF(buf, "The CV %lu is not in the priority list.", val_red_point);
22727  SU2_MPI::Error(string(buf), CURRENT_FUNCTION);
22728  }
22729 
22730  if (Number_Neighbors != 0) {
22731 
22732  /*--- Remove the control volume ---*/
22733  RemoveCV(val_red_point);
22734 
22735  /*--- Increase the priority ---*/
22736  AddCV(val_red_point, Number_Neighbors-1);
22737 
22738  }
22739 
22740 }
22741 
22743  unsigned short iPoint;
22744  unsigned long jPoint;
22745 
22746  cout << endl;
22747  for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++) {
22748  cout << "Number of neighbors " << iPoint <<": ";
22749  for (jPoint = 0; jPoint < QueueCV[iPoint].size(); jPoint ++) {
22750  cout << QueueCV[iPoint][jPoint] << " ";
22751  }
22752  cout << endl;
22753  }
22754 
22755 }
22756 
22758  unsigned long iPoint;
22759 
22760  for (iPoint = 0; iPoint < nPoint; iPoint ++)
22761  cout << "Control Volume: " << iPoint <<" Priority: " << Priority[iPoint] << endl;
22762 
22763 }
22764 
22766  if (QueueCV.size() != 0) return QueueCV[QueueCV.size()-1][0];
22767  else return -1;
22768 }
22769 
22771  unsigned short iPoint;
22772 
22773  /*--- In case there is only the no agglomerated elements,
22774  check if they can be agglomerated or we have already finished ---*/
22775  bool check = true;
22776 
22777  if ( QueueCV.size() == 1 ) {
22778  for (iPoint = 0; iPoint < QueueCV[0].size(); iPoint ++) {
22779  if (RightCV[QueueCV[0][iPoint]]) { check = false; break; }
22780  }
22781  }
22782  else {
22783  for (iPoint = 1; iPoint < QueueCV.size(); iPoint ++)
22784  if (QueueCV[iPoint].size() != 0) { check = false; break;}
22785  }
22786 
22787  return check;
22788 }
22789 
22790 unsigned long CMultiGridQueue::TotalCV(void) {
22791  unsigned short iPoint;
22792  unsigned long TotalCV;
22793 
22794  TotalCV = 0;
22795  for (iPoint = 0; iPoint < QueueCV.size(); iPoint ++)
22796  if (QueueCV[iPoint].size() != 0) { TotalCV += QueueCV[iPoint].size(); }
22797 
22798  return TotalCV;
22799 }
22800 
22801 void CMultiGridQueue::Update(unsigned long iPoint, CGeometry *fine_grid) {
22802  unsigned short iNode;
22803  unsigned long jPoint;
22804 
22805  RemoveCV(iPoint);
22806  for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) {
22807  jPoint = fine_grid->node[iPoint]->GetPoint(iNode);
22808  if (fine_grid->node[jPoint]->GetAgglomerate() == false)
22809  IncrPriorityCV(jPoint);
22810  }
22811 
22812 }
#define AD_BEGIN_PASSIVE
#define AD_END_PASSIVE
#define C(i, j)
#define B(i, j)
#define A(i, j)
bool IsEmpty(void) const
Function, which returns whether or not the ADT is empty.
Class for storing an ADT of (linear) elements in an arbitrary number of dimensions.
void DetermineNearestElement(const su2double *coor, su2double &dist, unsigned short &markerID, unsigned long &elemID, int &rankID)
Function, which determines the nearest element in the ADT for the given coordinate.
static void Error(std::string ErrorMsg, std::string FunctionName)
static void Barrier(Comm comm)
static void Probe(int source, int tag, Comm comm, Status *status)
static int GetSize()
static void Recv(void *buf, int count, Datatype datatype, int dest, int tag, Comm comm, Status *status)
static void Get_count(Status *status, Datatype datatype, int *count)
static void Gather(void *sendbuf, int sendcnt, Datatype sendtype, void *recvbuf, int recvcnt, Datatype recvtype, int root, Comm comm)
static void Isend(void *buf, int count, Datatype datatype, int dest, int tag, Comm comm, Request *request)
static void Allgather(void *sendbuf, int sendcnt, Datatype sendtype, void *recvbuf, int recvcnt, Datatype recvtype, Comm comm)
static void Scatter(void *sendbuf, int sendcnt, Datatype sendtype, void *recvbuf, int recvcnt, Datatype recvtype, int root, Comm comm)
static void Allreduce(void *sendbuf, void *recvbuf, int count, Datatype datatype, Op op, Comm comm)
static void Waitall(int nrequests, Request *request, Status *status)
static int GetRank()
static void Reduce(void *sendbuf, void *recvbuf, int count, Datatype datatype, Op op, int root, Comm comm)
static void Alltoall(void *sendbuf, int sendcount, Datatype sendtype, void *recvbuf, int recvcount, Datatype recvtype, Comm comm)
static void Comm_size(Comm comm, int *size)
static void Waitany(int nrequests, Request *request, int *index, Status *status)
static void Irecv(void *buf, int count, Datatype datatype, int source, int tag, Comm comm, Request *request)
static void Bcast(void *buf, int count, Datatype datatype, int root, Comm comm)
static void Sendrecv(void *sendbuf, int sendcnt, Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcnt, Datatype recvtype, int source, int recvtag, Comm comm, Status *status)
Main class for defining the problem; basically this class reads the configuration file,...
su2double * GetPeriodicTranslate(unsigned short val_index)
Get the translation vector for a periodic transformation.
string GetMarker_ActDiskInlet_TagBound(unsigned short val_marker)
Get the index of the surface defined in the geometry file.
string GetMarker_ActDiskOutlet_TagBound(unsigned short val_marker)
Get the index of the surface defined in the geometry file.
su2double GetRotation_Rate_Y(unsigned short val_iZone)
Get the angular velocity of the mesh about the y-axis.
void SetnMarker_All(unsigned short val_nmarker)
Stores the number of marker in the simulation.
unsigned short GetMarker_All_GeoEval(unsigned short val_marker)
Get the monitoring information for a marker val_marker.
long GetUnst_AdjointIter(void)
Get the starting direct iteration number for the unsteady adjoint (reverse time integration).
unsigned short GetKind_Solver(void)
Governing equations of the flow (it can be different from the run time equation).
void SetCFL(unsigned short val_mesh, su2double val_cfl)
Get the Courant Friedrich Levi number for each grid.
unsigned short GetMarker_CfgFile_PerBound(string val_marker)
Get the periodic information from the config definition of the marker val_marker.
unsigned short GetnMarker_Shroud(void)
Get number of shroud markers.
unsigned short GetiInst(void)
Get the current instance.
su2double GetWall_HeatFlux(string val_index)
Get the wall heat flux on a constant heat flux boundary.
unsigned long GetnExtIter(void)
Get the number of external iterations.
su2double GetRefSharpEdges(void)
Get the reference coefficient for detecting sharp edges.
void SetMarker_All_TurbomachineryFlag(unsigned short val_marker, unsigned short val_turboflag)
Set a flag to the marker val_marker part of the Turbomachinery (read from the config file).
void SetPeriodicCenter(unsigned short val_index, su2double *center)
Set the rotation center for a periodic transformation.
su2double * GetPeriodicCenter(unsigned short val_index)
Get the rotation center for a periodic transformation.
su2double GetGeo_Waterline_Location(void)
Get the location of the waterline.
unsigned short GetMarker_All_Turbomachinery(unsigned short val_marker)
Get the Turbomachinery information for a marker val_marker.
unsigned short GetnSpanWiseSections(void)
number span-wise sections to compute 3D BC and performance for turbomachinery.
void SetPeriodicTranslate(unsigned short val_index, su2double *translate)
Set the translation vector for a periodic transformation.
string GetMesh_FileName(void)
Get name of the input grid.
unsigned short GetnWingStations(void)
Get the number of sections for computing internal volume.
su2double GetMotion_Origin_X(unsigned short val_iZone)
Get x-coordinate of the mesh motion origin.
unsigned short GetnTimeInstances(void)
Retrieves the number of periodic time instances for Harmonic Balance.
unsigned short GetnMarker_All(void)
Get the total number of boundary markers.
void SetAoA(su2double val_AoA)
Set the angle of attack.
unsigned short GetMarker_CfgFile_GeoEval(string val_marker)
Get the monitoring information from the config definition for the marker val_marker.
bool GetRead_Binary_Restart(void)
Flag for whether binary SU2 native restart files are read.
unsigned short GetMarker_All_DV(unsigned short val_marker)
Get the DV information for a marker val_marker.
void SetMarker_All_Turbomachinery(unsigned short val_marker, unsigned short val_turbo)
Set if a marker val_marker is part of the Turbomachinery (read from the config file).
bool GetDiscard_InFiles(void)
Get information about whether to use fixed CL mode.
su2double * GetPeriodicRotation(unsigned short val_index)
Get the rotation angles for a periodic transformation.
su2double GetTranslation_Rate_X(unsigned short val_iZone)
Get the translational velocity of the mesh in the x-direction.
unsigned short GetnPeriodicIndex(void)
Get the total number of SEND_RECEIVE periodic transformations.
void SetMarker_All_TagBound(unsigned short val_marker, string val_index)
Set the value of the index val_index (read from the geometry file) for the marker val_marker.
unsigned short GetKind_Turb_Model(void)
Get the kind of the turbulence model.
void SetMarker_All_Designing(unsigned short val_marker, unsigned short val_designing)
Set if a marker val_marker is going to be designed val_designing (read from the config file).
su2double GetDelta_UnstTimeND(void)
If we are prforming an unsteady simulation, there is only one value of the time step for the complete...
su2double GetTranslation_Rate_Z(unsigned short val_iZone)
Get the translational velocity of the mesh in the z-direction.
su2double GetAoS(void)
Get the angle of sideslip of the body. It relates to the rotation of the aircraft centerline from the...
void SetPeriodicRotation(unsigned short val_index, su2double *rotation)
Set the rotation angles for a periodic transformation.
unsigned short GetUnsteady_Simulation(void)
Provides information about the time integration, and change the write in the output files information...
unsigned short GetKind_SU2(void)
Get the kind of SU2 software component.
unsigned short GetnMarker_ActDiskInlet(void)
Get the total number of boundary markers.
string GetSolution_AdjFileName(void)
Get the name of the file with the solution of the adjoint flow problem with drag objective function.
unsigned short GetMarker_All_KindBC(unsigned short val_marker)
Get the kind of boundary for each marker.
vector< string > fields
Tags for the different fields in a restart file.
su2double GetCFL(unsigned short val_mesh)
Get the Courant Friedrich Levi number for each grid.
void SetMarker_All_ZoneInterface(unsigned short val_marker, unsigned short val_fsiinterface)
Set if a marker val_marker is part of the FSI interface val_plotting (read from the config file).
unsigned short GetMarker_All_PyCustom(unsigned short val_marker)
Get the Python customization for a marker val_marker.
unsigned short GetMarker_CfgFile_Designing(string val_marker)
Get the monitoring information from the config definition for the marker val_marker.
su2double * GetPeriodicTranslation(string val_marker)
Translation vector for a rotational periodic boundary.
unsigned short GetnSpanMaxAllZones(void)
number span-wise sections to compute performance for turbomachinery.
su2double GetAoA(void)
Get the angle of attack of the body. This is the angle between a reference line on a lifting body (of...
unsigned short GetMarker_CfgFile_TurbomachineryFlag(string val_marker)
Get the TurboPerformance flag information from the config definition for the marker val_marker.
string GetMarker_Shroud(unsigned short val_marker)
Get the marker shroud.
bool GetGrid_Movement(void)
Get information about the grid movement.
void SetMarker_All_Moving(unsigned short val_marker, unsigned short val_moving)
Set if a marker val_marker is going to be moved val_moving (read from the config file).
unsigned short GetMarker_CfgFile_MixingPlaneInterface(string val_marker)
Get the MixingPlane interface information from the config definition for the marker val_marker.
unsigned short GetnMarker_NearFieldBound(void)
Get the total number of boundary markers.
su2double GetSemiSpan(void)
Get the wing semi span.
unsigned short GetKind_Regime(void)
Governing equations of the flow (it can be different from the run time equation).
su2double * GetPeriodicRotCenter(string val_marker)
Center of rotation for a rotational periodic boundary.
void SetAoS(su2double val_AoS)
Set the angle of attack.
void SetMarker_All_PyCustom(unsigned short val_marker, unsigned short val_PyCustom)
Set if a marker val_marker is going to be customized in Python val_PyCustom (read from the config fil...
bool GetActDisk_DoubleSurface(void)
Actuator disk defined with a double surface.
long GetVisualize_CV(void)
Get the node number of the CV to visualize.
unsigned short GetnMarker_ActDiskOutlet(void)
Get the total number of boundary markers.
void SetRefArea(su2double val_area)
In case the RefArea is equal to 0 then, it is necessary to compute a reference area,...
unsigned short GetMarker_CfgFile_DV(string val_marker)
Get the DV information from the config definition for the marker val_marker.
string GetSurfAdjCoeff_FileName(void)
Get the name of the file with the surface information for the adjoint problem.
su2double GetIsothermal_Temperature(string val_index)
Get the wall temperature (static) at an isothermal boundary.
su2double GetOmega_Ref(void)
Get the value of the reference angular velocity for non-dimensionalization.
su2double GetRotation_Rate_Z(unsigned short val_iZone)
Get the angular velocity of the mesh about the z-axis.
short GetMarker_All_SendRecv(unsigned short val_marker)
Get the send-receive information for a marker val_marker.
su2double GetHarmonicBalance_Period(void)
Retrieves the period of oscillations to be used with Harmonic Balance.
unsigned short GetMarker_Periodic_Donor(string val_marker)
Get the rotationally periodic donor marker for boundary val_marker.
unsigned short GetKind_SpanWise(void)
Get the kind of turbomachinery architecture.
void SetMarker_All_Analyze(unsigned short val_marker, unsigned short val_analyze)
Set if a marker val_marker is going to be plot val_plotting (read from the config file).
void SetMarker_All_SendRecv(unsigned short val_marker, short val_index)
Set if a marker val_marker is going to be sent or receive val_index from another domain.
unsigned short GetMarker_All_Plotting(unsigned short val_marker)
Get the plotting information for a marker val_marker.
void SetMarker_All_GeoEval(unsigned short val_marker, unsigned short val_geoeval)
Set if a marker val_marker is going to be monitored val_monitoring (read from the config file).
su2double * GetPeriodicRotAngles(string val_marker)
Angles of rotation for a rotational periodic boundary.
unsigned short GetnMarker_Turbomachinery(void)
number Turbomachinery performance option specified from config file.
su2double GetVelocity_Ref(void)
Get the value of the reference velocity for non-dimensionalization.
unsigned short GetMarker_CfgFile_PyCustom(string val_marker)
Get the Python customization information from the config definition for the marker val_marker.
string GetUnsteady_FileName(string val_filename, int val_iter)
Augment the input filename with the iteration number for an unsteady file.
unsigned short GetMarker_All_Monitoring(unsigned short val_marker)
Get the monitoring information for a marker val_marker.
string GetMarker_All_TagBound(unsigned short val_marker)
Get the index of the surface defined in the geometry file.
void SetAoA_Sens(su2double val_AoA_sens)
Set the angle of attack.
static unsigned short GetnZone(string val_mesh_filename, unsigned short val_format, CConfig *config)
Gets the number of zones in the mesh file.
unsigned short GetnMarker_TurboPerformance(void)
number Turbomachinery performance option specified from config file.
void SetMarker_All_Monitoring(unsigned short val_marker, unsigned short val_monitoring)
Set if a marker val_marker is going to be monitored val_monitoring (read from the config file).
su2double GetNacelleLocation(unsigned short val_index)
Get the defintion of the nacelle location.
unsigned short GetGeo_Description(void)
Get Description of the geometry to be analyzed.
void SetMGLevels(unsigned short val_nMGLevels)
Set the number of multigrid levels.
su2double GetRotation_Rate_X(unsigned short val_iZone)
Get the angular velocity of the mesh about the x-axis.
su2double GetDelta_UnstTime(void)
If we are prforming an unsteady simulation, there is only one value of the time step for the complete...
bool GetWrt_Unsteady(void)
Get information about writing unsteady headers and file extensions.
short GetMarker_All_PerBound(unsigned short val_marker)
Get an internal index that identify the periodic boundary conditions.
su2double GetTranslation_Rate_Y(unsigned short val_iZone)
Get the translational velocity of the mesh in the y-direction.
void SetnSpanWiseSections(unsigned short nSpan)
set number span-wise sections to compute 3D BC and performance for turbomachinery.
bool GetActDisk_SU2_DEF(void)
Actuator disk defined with a double surface.
su2double GetDomainVolume(void)
Get the volume of the whole domain using the fine grid, this value is common for all the grids in the...
unsigned short GetMarker_All_TurbomachineryFlag(unsigned short val_marker)
Get the Turbomachinery flag information for a marker val_marker.
unsigned short GetMarker_CfgFile_KindBC(string val_marker)
Get the boundary information (kind of boundary) in the config information of the marker val_marker.
unsigned short GetMarker_CfgFile_Moving(string val_marker)
Get the motion information from the config definition for the marker val_marker.
unsigned short GetiZone(void)
Provides the number of varaibles.
su2double GetMotion_Origin_Y(unsigned short val_iZone)
Get y-coordinate of the mesh motion origin.
unsigned short GetOutput_FileFormat(void)
Get the format of the output solution.
void SetMarker_All_MixingPlaneInterface(unsigned short val_marker, unsigned short val_mixplan_interface)
Set if a marker val_marker is part of the MixingPlane interface (read from the config file).
su2double GetLength_Ref(void)
Get the value of the reference length for non-dimensionalization. This value should always be 1 inter...
su2double GetStations_Bounds(unsigned short val_var)
Get the value of the limits for the sections.
bool GetAxisymmetric(void)
Get information about the axisymmetric frame.
void SetSemiSpan(su2double val_semispan)
In case the SemiSpan is equal to 0 then, it is necessary to compute the max y distance,...
void SetDomainVolume(su2double val_volume)
Set the value of the domain volume computed on the finest grid.
void SetMarker_All_PerBound(unsigned short val_marker, short val_perbound)
Set if a marker val_marker is going to be periodic val_perbound (read from the config file).
unsigned short GetMesh_FileFormat(void)
Get the format of the input/output grid.
su2double GetRefArea(void)
Get the reference area for non dimensional coefficient computation. If the value from the is 0 then,...
void SetnBlades(unsigned short val_iZone, su2double nblades)
number Turbomachinery blades computed using the pitch information.
string GetObjFunc_Extension(string val_filename)
Append the input filename string with the appropriate objective function extension.
bool GetFrozen_Visc_Disc(void)
Provides information about the way in which the turbulence will be treated by the disc....
unsigned short Get_nSpanWiseSections_User(void)
number span-wise sections to compute 3D BC and performance for turbomachinery specified by the user.
void SetMarker_All_KindBC(unsigned short val_marker, unsigned short val_boundary)
Set the value of the boundary val_boundary (read from the config file) for the marker val_marker.
unsigned short GetMarker_CfgFile_Monitoring(string val_marker)
Get the monitoring information from the config definition for the marker val_marker.
void SetMarker_All_DV(unsigned short val_marker, unsigned short val_DV)
Set if a marker val_marker is going to be affected by design variables val_moving (read from the conf...
su2double GetMotion_Origin_Z(unsigned short val_iZone)
Get z-coordinate of the mesh motion origin.
void SetAoS_Offset(su2double val_AoS_offset)
Set the off set sideslip angle.
void SetnPeriodicIndex(unsigned short val_index)
Set the total number of SEND_RECEIVE periodic transformations.
unsigned short GetMarker_CfgFile_Analyze(string val_marker)
Get the plotting information from the config definition for the marker val_marker.
unsigned short GetMarker_CfgFile_Turbomachinery(string val_marker)
Get the TurboPerformance information from the config definition for the marker val_marker.
void SetAoA_Offset(su2double val_AoA_offset)
Set the off set angle of attack.
void SetMarker_All_Plotting(unsigned short val_marker, unsigned short val_plotting)
Set if a marker val_marker is going to be plot val_plotting (read from the config file).
unsigned short GetnMGLevels(void)
Get the number of multigrid levels.
unsigned short GetnMarker_Max(void)
Get the total number of boundary markers.
string GetMultizone_FileName(string val_filename, int val_iZone)
Append the zone index to the restart or the solution files.
unsigned short GetKind_TurboMachinery(unsigned short val_iZone)
Get the kind of turbomachinery architecture.
unsigned short GetSystemMeasurements(void)
Governing equations of the flow (it can be different from the run time equation).
unsigned short GetMarker_CfgFile_TagBound(string val_marker)
Get the index in the config information of the marker val_marker.
unsigned short GetMarker_CfgFile_Plotting(string val_marker)
Get the plotting information from the config definition for the marker val_marker.
unsigned short GetMarker_CfgFile_ZoneInterface(string val_marker)
Get the FSI interface information from the config definition for the marker val_marker.
void SetFreeStreamTurboNormal(su2double *turboNormal)
Set freestream turbonormal for initializing solution.
unsigned short GetnMarker_InterfaceBound(void)
Get the total number of boundary markers.
Class for defining an edge.
void AddNormal(su2double *val_face_normal)
Add a vector to the normal vector.
void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG)
Set the face that correspond to an edge.
void SetCoord_CG(su2double **val_coord)
Set the center of gravity of the edge.
void GetNormal(su2double *val_normal)
Copy the the normal vector of a face.
su2double GetCG(unsigned short val_dim)
Obtain the centre of gravity of the edge.
su2double GetVolume(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG, su2double *val_coord_Point)
Compute Volume associated to each edge.
unsigned long GetNode(unsigned short val_node)
Get the nodes of the edge.
unsigned short GetnNodes(void)
Get the number of nodes of an element.
Parent class for defining the geometry of the problem (complete geometry, multigrid agglomerated geom...
unsigned long Global_nElemDomain
Total number of elements in a simulation across all processors (excluding halos).
unsigned long nelem_edge
Number of edges in the mesh.
unsigned long Global_nelem_triangle
Total number of triangles in the mesh across all processors.
virtual void SetFaces(void)
A virtual member.
su2double *** AverageGridVel
Average boundary normal at each span wise section for each marker.
void ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, su2double MinXCoord, su2double MaxXCoord, su2double MinYCoord, su2double MaxYCoord, su2double MinZCoord, su2double MaxZCoord, su2double *FlowVariable, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil, vector< su2double > &Variable_Airfoil, bool original_surface, CConfig *config)
A virtual member.
vector< su2double > XCoordList
Vector containing points appearing on a single plane.
virtual void SetCustomBoundary(CConfig *config)
Set the data containers for customized boundary conditions.
long FindEdge(unsigned long first_point, unsigned long second_point)
Get the edge index from using the nodes of the edge.
virtual void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker)
A virtual member.
void UpdateGeometry(CGeometry **geometry_container, CConfig *config)
Update the multi-grid structure and the wall-distance.
unsigned short nTurboPerf
Number of Span wise section for each turbo marker, indexed by marker. Needed for deallocation.
unsigned long * nNewElem_Bound
Number of new periodic elements of the boundary.
CEdge ** edge
Edge vector (dual grid information).
unsigned long Global_nelem_quad
Total number of quadrangles in the mesh across all processors.
unsigned long Global_nelem_tetra
Total number of tetrahedra in the mesh across all processors.
su2double ** SpanArea
Average tangential rotational speed at each span wise section for each marker.
virtual unsigned long GetGlobal_nPointDomain()
A virtual member.
unsigned long nElem
Number of elements of the mesh.
unsigned long nelem_quad
Number of quadrangles in the mesh.
unsigned long nEdge
Number of edges of the mesh.
su2double ** MinAngularCoord
Max angular pitch at each span wise section for each marker.
void ComputeSurf_Curvature(CConfig *config)
Find and store all vertices on a sharp corner in the geometry.
virtual void SetControlVolume(CConfig *config, unsigned short action)
A virtual member.
unsigned long nelem_prism
Number of prisms in the mesh.
bool SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], su2double vert0[3], su2double vert1[3], su2double vert2[3])
Segment Intersects Triangle.
unsigned short GetnDim(void)
Get number of coordinates.
unsigned long * nElem_Bound
Number of elements of the boundary.
void RegisterCoordinates(CConfig *config)
Register the coordinates of the mesh nodes.
su2double ** MinRelAngularCoord
Max angular pitch at each span wise section for each marker.
su2double GetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex)
Get the value of the customized temperature at a specified vertex on a specified marker.
unsigned long nPointDomain
Number of real points of the mesh.
CPrimalGrid *** bound
Boundary vector (primal grid information).
unsigned long ** nTotVertexSpan
number of vertexes for span wise section for each marker.
unsigned short GetnMarker(void)
Get number of markers.
su2double ** CustomBoundaryHeatFlux
unsigned long nelem_edge_bound
Number of edges on the mesh boundaries.
su2double ** SpanAreaOut
su2double ** SpanWiseValue
Span wise values for each turbo marker.
void SetSpline(vector< su2double > &x, vector< su2double > &y, unsigned long n, su2double yp1, su2double ypn, vector< su2double > &y2)
Given arrays x[1..n] and y[1..n] containing a tabulated function, i.e., yi = f(xi),...
int rank
MPI Rank.
unsigned long Global_nelem_prism
Total number of prisms in the mesh across all processors.
unsigned long GetnElem(void)
Get number of elements.
unsigned long GetnElem_Bound(unsigned short val_marker)
Get the number of boundary elements.
unsigned long nelem_quad_bound
Number of quads on the mesh boundaries.
CTurboVertex **** turbovertex
Boundary Vertex vector ordered for turbomachinery calculation(dual grid information).
unsigned long GetnPointDomain(void)
Get number of real points (that belong to the domain).
CPrimalGrid *** newBound
Boundary vector for new periodic elements (primal grid information).
su2double ** TurboRadius
Min relative angular coord at each span wise section for each marker.
virtual unsigned long GetGlobal_nElemDomain()
A virtual member.
unsigned long xadj_size
unsigned long Global_nElem
Total number of elements in a simulation across all processors (all types).
unsigned long GetnVertex(unsigned short val_marker)
Get number of vertices.
su2double ** CustomBoundaryTemperature
virtual void SetCoord(CGeometry *geometry)
A virtual member.
virtual void Set_MPI_GridVel(CConfig *config)
A virtual member.
unsigned short * nSpanWiseSections
Number of Span wise section for each turbo marker, indexed by inflow/outflow.
short * Marker_All_SendRecv
virtual unsigned long GetGlobal_nElem()
A virtual member.
unsigned long * npoint_procs
void UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config)
Update the multi-grid structure for the customized boundary conditions.
string GetMarker_Tag(unsigned short val_marker)
Get the index of a marker.
vector< vector< unsigned long > > Plane_points
Vector containing points appearing on a single plane.
unsigned long * starting_node
virtual void Set_MPI_Coord(CConfig *config)
A virtual member.
vector< unsigned long > PeriodicElem[MAX_NUMBER_PERIODIC]
PeriodicElem[Periodic bc] and return the elements that must be sent.
CVertex *** vertex
Boundary Vertex vector (dual grid information).
unsigned long Global_nPointDomain
Total number of nodes in a simulation across all processors (excluding halos).
virtual void SetMaxLength(CConfig *config)
A virtual member.
vector< vector< su2double > > Zcoord_plane
Vector containing z coordinates of new points appearing on a single plane.
su2double ** TurboRadiusIn
Area at each span wise section for each turbomachinery marker.
void TestGeometry(void)
Create a file for testing the geometry.
unsigned short nMarker
Number of different markers of the mesh.
unsigned long nelem_triangle
Number of triangles in the mesh.
virtual void SetCoord_CG(void)
A virtual member.
unsigned long nPoint
Number of points of the mesh.
unsigned long * nPoint_Linear
su2double GetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex)
Get the value of the customized normal heat flux at a specified vertex on a specified marker.
virtual void SetVertex(void)
A virtual member.
vector< vector< su2double > > FaceArea_plane
Vector containing area/volume associated with new points appearing on a single plane.
map< unsigned long, unsigned long > Global_to_Local_Elem
unsigned long nelem_hexa
Number of hexahedra in the mesh.
bool RayIntersectsTriangle(su2double orig[3], su2double dir[3], su2double vert0[3], su2double vert1[3], su2double vert2[3], su2double *intersect)
Ray Intersects Triangle (Moller and Trumbore algorithm)
unsigned short nDim
Number of dimension of the problem.
virtual void ComputeWall_Distance(CConfig *config)
A virtual member.
void RegisterOutput_Coordinates(CConfig *config)
Register the coordinates of the mesh nodes as output.
unsigned long * ending_node
unsigned short * nSpanSectionsByMarker
vector< vector< su2double > > Ycoord_plane
Vector containing y coordinates of new points appearing on a single plane.
unsigned short GetnZone(void)
Get number of zones.
string * Tag_to_Marker
If you know the index of the boundary (depend of the grid definition), it gives you the maker (where ...
virtual ~CGeometry(void)
Destructor of the class.
unsigned long GetnPoint(void)
Get number of points.
su2double ** SpanAreaIn
Average tangential rotational speed at each span wise section for each turbomachinery marker.
vector< unsigned long > PeriodicPoint[MAX_NUMBER_PERIODIC][2]
PeriodicPoint[Periodic bc] and return the point that must be sent [0], and the image point in the per...
unsigned long adjacency_size
unsigned long nelem_tetra
Number of tetrahedra in the mesh.
unsigned long nPointNode
Size of the node array allocated to hold CPoint objects.
virtual unsigned long GetGlobal_nPoint()
A virtual member.
int size
MPI Size.
vector< vector< su2double > > Xcoord_plane
Vector containing x coordinates of new points appearing on a single plane.
bool SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp)
Compute the intersection between a segment and a plane.
unsigned long Global_nelem_edge
Total number of edges in the mesh across all processors.
su2double *** AverageTurboNormal
max number of vertexes for each span section for each marker flag.
su2double ** TangGridVelOut
CGeometry(void)
Constructor of the class.
CPrimalGrid ** face
Face vector (primal grid information).
unsigned long nelem_triangle_bound
Number of triangles on the mesh boundaries.
unsigned long Global_nPoint
Total number of nodes in a simulation across all processors (including halos).
void SetnVertexSpanMax(unsigned short marker_flag, unsigned long nVertMax)
Get number of vertices.
su2double ** AverageTangGridVel
Average boundary grid velocity at each span wise section for each marker.
unsigned long nelem_pyramid
Number of pyramids in the mesh.
su2double Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord)
Get the distance between a plane (defined by three point) and a point.
su2double *** AverageNormal
Average boundary normal at each span wise section for each marker in the turbomachinery frame of refe...
su2double GetSpline(vector< su2double > &xa, vector< su2double > &ya, vector< su2double > &y2a, unsigned long n, su2double x)
Given the arrays xa[1..n] and ya[1..n], which tabulate a function (with the xai’s in order),...
su2double ** MaxAngularCoord
Area at each span wise section for each marker.
virtual void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker)
A virtual member.
virtual void SetBoundControlVolume(CConfig *config, unsigned short action)
A virtual member.
CPrimalGrid ** elem
Element vector (primal grid information).
unsigned long Max_GlobalPoint
Greater global point in the domain local structure.
CPoint ** node
Node vector (dual grid information).
unsigned long Global_nelem_pyramid
Total number of pyramids in the mesh across all processors.
unsigned long * nVertex
Number of vertex for each marker.
unsigned long nFace
Number of faces of the mesh.
su2double ** TangGridVelIn
Radius at each span wise section for each marker.
su2double ** TurboRadiusOut
bool CheckEdge(unsigned long first_point, unsigned long second_point)
Get the edge index from using the nodes of the edge.
unsigned long Global_nelem_hexa
Total number of hexahedra in the mesh across all processors.
unsigned short nZone
Number of zones in the problem.
void SetEdges(void)
A virtual member.
bool SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2])
Segment Intersects Line (for 2D FFD Intersection)
Class for hexahedron element definition.
Class for line element definition.
void SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config)
Set the grid velocity at each node in the coarse mesh level based on a restriction from a finer mesh.
void SetGridVelocity(CConfig *config, unsigned long iter)
Set the grid velocity at each node in the coarse mesh level.
void SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action)
Set the edge structure of the agglomerated control volume.
CMultiGridGeometry(CGeometry ****geometry, CConfig **config_container, unsigned short iMesh, unsigned short iZone, unsigned short iInst)
Constructor of the class.
void FindNormal_Neighbor(CConfig *config)
Find and store the closest neighbor to a vertex.
void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker)
Set a representative wall normal heat flux of the agglomerated control volume on a particular boundar...
void SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print)
Set the rotational velocity at each grid point on a coarse mesh.
void SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print)
Set the translational velocity at each grid point on a coarse mesh.
bool GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config)
Determine if a can be agglomerated using geometrical criteria.
void SetCoord(CGeometry *geometry)
Set a representative coordinates of the agglomerated control volume.
void SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action)
Set boundary vertex structure of the agglomerated control volume.
void SetShroudVelocity(CConfig *config)
Set the rotational velocity of the points on the shroud markers to 0.0.
bool SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config)
Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed.
~CMultiGridGeometry(void)
Destructor of the class.
void SetGeometryPlanes(CConfig *config)
Indentify geometrical planes in the mesh.
void SetSuitableNeighbors(vector< unsigned long > *Suitable_Indirect_Neighbors, unsigned long iPoint, unsigned long Index_CoarseCV, CGeometry *fine_grid)
Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed.
void MatchActuator_Disk(CConfig *config)
Mach the near field boundary condition.
void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker)
Set a representative wall temperature of the agglomerated control volume on a particular boundary mar...
void MatchInterface(CConfig *config)
Mach the interface boundary condition.
void MatchNearField(CConfig *config)
Mach the near field boundary condition.
void SetPoint_Connectivity(void)
Function declaration to avoid partially overridden classes.
Class for a multigrid queue system.
void VisualizeQueue(void)
Visualize the control volume queue.
unsigned long TotalCV(void)
Total number of control volume in the queue.
void RemoveCV(unsigned long val_remove_point)
Remove a CV from the list.
bool EmptyQueue(void)
Check if the queue is empty.
~CMultiGridQueue(void)
Destructor of the class.
void VisualizePriority(void)
Visualize the priority list.
void MoveCV(unsigned long val_move_point, short val_number_neighbors)
Change a CV from a list to a different list.
void RedPriorityCV(unsigned long val_red_point)
Increase the priority of the CV.
void AddCV(unsigned long val_new_point, unsigned short val_number_neighbors)
Add a new CV to the list.
CMultiGridQueue(unsigned long val_npoint)
Constructor of the class.
void IncrPriorityCV(unsigned long val_incr_point)
Increase the priority of the CV.
long NextCV(void)
Find a new seed control volume.
void Update(unsigned long val_update_point, CGeometry *fine_grid)
Update the queue with the new control volume (remove the CV and increase the priority of the neighbor...
void SetPeriodicBoundary(CGeometry *geometry, CConfig *config)
Set the periodic boundaries of the grid.
void SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename)
Write the .su2 file.
void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file)
Set the Tecplot file.
~CPeriodicGeometry(void)
Destructor of the class.
CPeriodicGeometry(CGeometry *geometry, CConfig *config)
Constructor of the class.
void SetColorGrid(CConfig *config)
Set the domains for grid grid partitioning using METIS.
void SetSensitivity(CConfig *config)
Read the sensitivity from adjoint solution file and store it.
void SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config)
Set the output file for boundaries in Tecplot.
void SetPoint_Connectivity(void)
Set points which surround a point.
su2double Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, su2double *LeadingEdge_i, su2double *TrailingEdge_i)
Compute the dihedral of a wing.
void InitiateComms(void *bufSend, int *nElemSend, SU2_MPI::Request *sendReq, void *bufRecv, int *nElemRecv, SU2_MPI::Request *recvReq, unsigned short countPerElem, unsigned short commType)
Routine to launch non-blocking sends and recvs amongst all processors.
void SetBoundaries(CConfig *config)
Set the send receive boundaries of the grid.
void DistributePoints(CConfig *config, CGeometry *geometry)
Distribute the grid points, including ghost points, across all ranks based on a ParMETIS coloring.
~CPhysicalGeometry(void)
Destructor of the class.
void SetElement_Connectivity(void)
Set elements which surround an element.
void SetBoundControlVolume(CConfig *config, unsigned short action)
Set boundary vertex structure of the control volume.
su2double Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the maximum thickness of an airfoil.
void SetCoord_Smoothing(unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config)
Do an implicit smoothing of the grid coordinates.
void GatherInOutAverageValues(CConfig *config, bool allocate)
Set turbo boundary vertex.
su2double Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the length of an airfoil.
void SetMaxLength(CConfig *config)
Set the maximum cell-center to cell-center distance for CVs.
void Compute_Nacelle(CConfig *config, bool original_surface, su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist)
Evaluate geometrical parameters of a wing.
void SetBoundVolume(void)
Set the volume element associated to each boundary element.
su2double Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the area of an airfoil.
su2double Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the chord of an airfoil.
void Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the leading/trailing edge location of an airfoil.
void SetSendReceive(CConfig *config)
Set the send receive boundaries of the grid.
su2double Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the chord of an airfoil.
void SetMeshFile(CConfig *config, string val_mesh_out_filename)
Write the .su2 file.
unsigned long GetGlobal_nPointDomain()
Retrieve total number of nodes in a simulation across all processors (excluding halos).
void SetTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate)
Set turbo boundary vertex.
void DistributeMarkerTags(CConfig *config, CGeometry *geometry)
Broadcast the marker tags for all boundaries from the master rank to all other ranks.
void Set_MPI_MaxLength(CConfig *config)
Perform the MPI communication for the max grid spacing.
su2double Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil, su2double &ZLoc)
Compute the thickness of an airfoil.
void SetGeometryPlanes(CConfig *config)
Indentify geometrical planes in the mesh.
void SetRCM_Ordering(CConfig *config)
Set a renumbering using a Reverse Cuthill-McKee Algorithm.
void Check_BoundElem_Orientation(CConfig *config)
Check the volume element orientation.
void Read_CGNS_Format_Parallel_FEM(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone)
Reads for the FEM solver the geometry of the grid and adjust the boundary conditions with the configu...
void ComputeWall_Distance(CConfig *config)
Computes the distance to the nearest no-slip wall for each grid node.
void Compute_Fuselage(CConfig *config, bool original_surface, su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, su2double &Fuselage_MaxCurvature)
Evaluate geometrical parameters of a wing.
void Check_Periodicity(CConfig *config)
Check the mesh for periodicity and deactivate multigrid if periodicity is found.
void DistributeColoring(CConfig *config, CGeometry *geometry)
Distributes the coloring from ParMETIS so that each rank has complete information about the local gri...
su2double Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the chord of an airfoil.
void CompleteComms(int nSends, SU2_MPI::Request *sendReq, int nRecvs, SU2_MPI::Request *recvReq)
Routine to complete the set of non-blocking communications launched with InitiateComms() with MPI_Wai...
void SetPositive_ZArea(CConfig *config)
Compute surface area (positive z-direction) for force coefficient non-dimensionalization.
void DistributeVolumeConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type)
Distribute the connectivity for a single volume element type across all ranks based on a ParMETIS col...
void LoadVolumeElements(CConfig *config, CGeometry *geometry)
Load the local volume elements after partitioning (owned and ghost) into the geometry class objects.
void SetGridVelocity(CConfig *config, unsigned long iter)
Set the grid velocity via finite differencing at each node.
void Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the leading/trailing edge location of a fuselage.
void MatchZone(CConfig *config, CGeometry *geometry_donor, CConfig *config_donor, unsigned short val_iZone, unsigned short val_nZone)
Mach the interface boundary condition.
void SetShroudVelocity(CConfig *config)
Set the rotational velocity of the points on the shroud markers to 0.
void SetControlVolume(CConfig *config, unsigned short action)
Set the edge structure of the control volume.
void Read_SU2_Format_Parallel_FEM(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone)
Reads for the FEM solver the geometry of the grid and adjust the boundary conditions with the configu...
void Set_MPI_Coord(CConfig *config)
Perform the MPI communication for the grid coordinates (dynamic meshes).
void SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print)
Set the rotational velocity at each node.
void ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate)
Set number of span wise level for turbomachinery computation.
void SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate)
Set turbo boundary vertex.
void GetQualityStatistics(su2double *statistics)
Compute some parameters about the grid quality.
void SetColorGrid_Parallel(CConfig *config)
Set the domains for grid grid partitioning using ParMETIS.
su2double Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, su2double *LeadingEdge_i, su2double *TrailingEdge_i, su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1)
Compute the curvature of a wing.
void Set_MPI_OldCoord(CConfig *config)
Perform the MPI communication for the grid coordinates (dynamic meshes) for restart purposes.
void MatchNearField(CConfig *config)
Mach the near field boundary condition.
void Set_MPI_GridVel(CConfig *config)
Perform the MPI communication for the grid velocities.
void DistributeSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type)
Distribute the connectivity for a single surface element type in all markers across all ranks based o...
void SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print)
Set the translational velocity at each node.
void MatchInterface(CConfig *config)
Mach the interface boundary condition.
void PartitionSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type)
Partition the marker connectivity held on the master rank according to a linear partitioning.
void SetBoundSensitivity(CConfig *config)
Read the sensitivity from an input file.
void Compute_Wing(CConfig *config, bool original_surface, su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, su2double &Wing_MinChord, su2double &Wing_MaxChord, su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, su2double &Wing_MinToC, su2double &Wing_MaxToC, su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, su2double &Wing_MaxCurvature, su2double &Wing_MaxDihedral)
Evaluate geometrical parameters of a wing.
void VisualizeControlVolume(CConfig *config, unsigned short action)
Visualize the structure of the control volume(s).
long GetGlobal_to_Local_Point(unsigned long val_ipoint)
Get the local index that correspond with the global numbering index.
CPhysicalGeometry(void)
Constructor of the class.
void MatchActuator_Disk(CConfig *config)
Mach the near field boundary condition.
su2double Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the twist of an airfoil.
void Read_SU2_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone)
Reads the geometry of the grid and adjust the boundary conditions with the configuration file in para...
void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file)
Set the Tecplot file.
void FindNormal_Neighbor(CConfig *config)
Find and store the closest neighbor to a vertex.
void Read_CGNS_Format_Parallel(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone)
Reads the geometry of the grid and adjust the boundary conditions with the configuration file in para...
void LoadSurfaceElements(CConfig *config, CGeometry *geometry)
Load the local surface elements after partitioning (owned and ghost) into the geometry class objects.
void SetCoord_CG(void)
Set the center of gravity of the face, elements and edges.
void LoadPoints(CConfig *config, CGeometry *geometry)
Load the local grid points after partitioning (owned and ghost) into the geometry class objects.
void SetBoundSensitivityTranspiration(CConfig *config)
Read the transpiration sensitivity from an input file.
void UpdateTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag)
update turbo boundary vertex.
void SetPeriodicBoundary(CConfig *config)
Set the periodic boundary conditions.
su2double Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the chord of an airfoil.
bool FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, unsigned short &face_second_elem)
Find repeated nodes between two elements to identify the common face.
void Check_IntElem_Orientation(CConfig *config)
Check the volume element orientation.
su2double Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector< su2double > &Xcoord_Airfoil, vector< su2double > &Ycoord_Airfoil, vector< su2double > &Zcoord_Airfoil)
Compute the chord of an airfoil.
Class for point definition (including control volume definition).
void SetCurvature(su2double val_curvature)
Set the value of the curvature at a surface node.
void SetGridVel(unsigned short val_dim, su2double val_gridvel)
Set the value of the grid velocity at the point.
void SetPhysicalBoundary(bool val_boundary)
Set if a point belong to the boundary.
void SetAgglomerate_Indirect(bool val_agglomerate)
Set information about if the indirect neighbors can be agglomerated.
su2double * GetCoord_Sum(void)
Get the value of the summed coordinates for implicit smoothing.
bool GetDomain(void)
For parallel computation, its indicates if a point must be computed or not.
unsigned long GetParent_CV(void)
Get the parent control volume of an agglomerated control volume.
void SetParent_CV(unsigned long val_parent_CV)
Set the parent control volume of an agglomerated control volume.
void SetCoord_n1(void)
Set the coordinates of the control volume at time n-1.
void SetnChildren_CV(unsigned short val_nchildren_CV)
Set the number of children of an agglomerated control volume.
su2double GetVolume(void)
Get area or volume of the control volume.
void SetEdge(long val_edge, unsigned short val_nEdge)
Set the edges that compose the control volume.
void AddVolume(su2double val_Volume)
Adds some area or volume of the CV.
void SetSolidBoundary(bool val_boundary)
Set if a point belong to the boundary.
void SetSharpEdge_Distance(su2double val_distance)
Set the value of the distance to a sharp edge.
void ResetBoundary(void)
Reset the boundary of a control volume.
void ResetElem(void)
Reset the elements of a control volume.
su2double * GetGridVel(void)
Get the value of the grid velocity at the point.
void SetCoord(unsigned short val_dim, su2double val_coord)
Set the coordinates for the control volume.
void SetWall_Distance(su2double val_distance)
Set the value of the distance to the nearest wall.
unsigned short GetnNeighbor(void)
Get the number of neighbor of a point.
su2double GetMaxLength(void)
Get the maximum cell-center to cell-center length.
bool GetAgglomerate(void)
Get information about if a control volume has been agglomerated.
unsigned long GetChildren_CV(unsigned short val_nchildren_CV)
Get the children control volume of an agglomerated control volume.
su2double * GetCoord_Old(void)
Get the value of the old coordinates for implicit smoothing.
su2double * GetCoord_n(void)
Get the coordinates of the control volume at time n.
void SetBoundary(unsigned short val_nmarker)
Set if a point belong to the boundary.
void SetPoint(unsigned long val_point)
Set the points that compose the control volume.
bool GetBoundary(void)
Provides information about if a point belong to the boundaries.
unsigned short GetColor(void)
Get the color of a point, the color indicates to which subdomain the point belong to.
su2double GetCoord(unsigned short val_dim)
Get the coordinates dor the control volume.
void SetVertex(long val_vertex, unsigned short val_nMarker)
Set the boundary vertex that compose the control volume.
unsigned short GetnChildren_CV(void)
Get the number of children of an agglomerated control volume.
void SetMaxLength(su2double val_max_length)
Set the max cell-center to cell-center length.
unsigned long GetElem(unsigned short val_elem)
Get all the elements that compose the control volume.
unsigned long GetPoint(unsigned short val_point)
Get all the points that compose the control volume.
void SetVolume(su2double val_Volume)
Set the volume of the control volume.
void SetChildren_CV(unsigned short val_nchildren_CV, unsigned long val_children_CV)
Set the children control volumes of an agglomerated control volume.
void SetColor(unsigned short val_color)
Set a color to the point that comes from the grid partitioning.
long GetEdge(unsigned short val_edge)
Get all the edges that compose the control volume.
void SetFlip_Orientation(void)
Set the coordinates for the control volume.
unsigned long GetGlobalIndex(void)
Get the global index in a parallel computation.
su2double * GetCoord_n1(void)
Get the coordinates of the control volume at time n-1.
void SetElem(unsigned long val_elem)
Set the elements that set the control volume.
void SetCoord_n(void)
Set the coordinates of the control volume at time n.
long GetVertex(unsigned short val_marker)
Get the vertex that compose the control volume for a marker.
void AddCoord_Sum(su2double *val_coord_sum)
Add the value of the coordinates to the Coord_Sum vector for implicit smoothing.
unsigned short GetnPoint(void)
Get the number of points that compose the control volume.
void ResetPoint(void)
Reset the points that compose the control volume.
void SetCoord_Old(su2double *val_coord_old)
Set the value of the vector Coord_Old for implicit smoothing.
unsigned short GetnElem(void)
Get the number of elements that compose the control volume.
void SetGlobalIndex(unsigned long val_globalindex)
Set the global index in a parallel computation.
bool GetAgglomerate_Indirect(void)
Get information about if the indirect neighbors can be agglomerated.
void SetDomain(bool val_domain)
For parallel computation, its indicates if a point must be computed or not.
Class to define the numerical primal grid.
virtual unsigned short GetnFaces(void)=0
A pure virtual member.
virtual unsigned short GetnNodes(void)=0
A pure virtual member.
su2double GetCG(unsigned short val_dim)
Get the center of gravity of an element (including edges).
virtual void SetRotation_Type(unsigned short val_rotation_type)
A pure virtual member.
su2double GetFaceCG(unsigned short val_face, unsigned short val_dim)
Get the CG of a face of an element.
virtual unsigned long GetNode(unsigned short val_node)=0
A pure virtual member.
virtual unsigned short GetnNeighbor_Nodes(unsigned short val_node)=0
A pure virtual member.
void SetCoord_CG(su2double **val_coord)
Set the center of gravity of an element (including edges).
virtual unsigned short GetnNodesFace(unsigned short val_face)=0
A pure virtual member.
void SetNeighbor_Elements(unsigned long val_elem, unsigned short val_face)
Set the elements that surround an element.
virtual void SetDomainElement(unsigned long val_domainelement)
A virtual member.
virtual unsigned short GetRotation_Type(void)
A pure virtual member.
virtual unsigned long GetDomainElement(void)
A virtual member.
virtual unsigned short GetFaces(unsigned short val_face, unsigned short val_index)=0
A pure virtual member.
virtual unsigned short GetVTK_Type(void)=0
A pure virtual member.
virtual void Change_Orientation(void)=0
A pure virtual member.
void SetGlobalIndex(unsigned long val_globalindex)
Set the global index for an element in a parallel computation.
virtual unsigned short GetNeighbor_Nodes(unsigned short val_node, unsigned short val_index)=0
virtual void SetNode(unsigned short val_node, unsigned long val_point)
A pure virtual member.
Class for prism element definition.
Class for pyramid element definition.
Class for quadrilateral element definition.
Class for tetrahedron element definition.
Class for triangle element definition.
Class for vertex definition for turbomachinery (equivalent to edges, but for the boundaries).
void SetTurboNormal(su2double *val_normal)
set Normal in the turbomachinery frame of reference.
void SetArea(su2double val_area)
set face Area.
void SetOldVertex(unsigned long val_vertex)
set vertex value not ordered.
void SetAngularCoord(su2double angCoord)
set angular coord.
su2double GetRelAngularCoord(void)
get angular coord.
su2double GetDeltaAngularCoord(void)
get angular coord.
void GetTurboNormal(su2double *val_normal)
Copy the the turbo normal vector of a face.
su2double GetArea(void)
get face Area associate to the vertex.
void SetDeltaAngularCoord(su2double deltaAngCoord)
set angular coord.
void SetRelAngularCoord(su2double minAngCoord)
set angular coord.
Class for vertex definition (equivalent to edges, but for the boundaries).
su2double * GetVarCoord(void)
Get the value of the coordinate variation due to a surface modification.
void GetNormal(su2double *val_normal)
Copy the the normal vector of a face.
void SetNormal_Neighbor(unsigned long val_Normal_Neighbor)
Set the index of the closest neighbor to a point on the boundaries.
void SetActDisk_Perimeter(bool val_actdisk_perimeter)
short GetRotation_Type(void)
Get the type of rotation associated to the vertex.
void SetNodes_Coord(su2double *val_coord_Edge_CG, su2double *val_coord_FaceElem_CG, su2double *val_coord_Elem_CG)
Set the face that correspond to a vertex.
void SetAuxTransp(su2double val_auxvar)
Set the value of an auxiliary tranpiration variable for gradient computation.
void AddAuxVar(su2double val_auxvar)
Add the value of an auxiliary variable for gradient computation.
void SetNormal(su2double *val_face_normal)
Set the normal vector.
void AddNormal(su2double *val_face_normal)
Add a vector to the normal vector.
unsigned long GetNode(void)
Get the node of the vertex.
void AddAuxTransp(su2double val_auxvar)
Add the value of an auxiliary tranpiration variable for gradient computation.
void SetAuxVar(su2double val_auxvar)
Set the value of an auxiliary variable for gradient computation.
void SetRotation_Type(short val_rotation_type)
Set the type of rotation associated to the vertex.
long GetDonorPoint(void)
Get the value of the periodic point of a vertex.
void SetDonorPoint(long val_periodicpoint, long val_processor)
Class for vertex element definition. This kind of element is used in the parallelization stuff.
codi::RealForward su2double
#define SPRINTF
double passivedouble
#define EPSILON
#define SUB(dest, v1, v2)
#define CROSS(dest, v1, v2)
#define DOT(v1, v2)
const su2double eps
machine epsilon
#define MPI_COMM_WORLD
#define MPI_INT
CBaseMPIWrapper::Status * MPI_STATUS_IGNORE
#define MPI_MAX
#define CURRENT_FUNCTION
#define MPI_UNSIGNED_LONG
#define MPI_SHORT
#define MPI_SUM
#define MPI_MIN
#define MPI_ANY_SOURCE
#define MPI_DOUBLE
#define MPI_LONG
#define MPI_CHAR
#define MPI_UNSIGNED_SHORT
void RegisterInput(su2double &data)
Registers the variable as an input. I.e. as a leaf of the computational graph.
void RegisterOutput(su2double &data)
Registers the variable as an output. I.e. as the root of the computational graph.
double GetValue(const su2double &data)
Get the (primitive) value of the datatype (needs to be implemented for each new type).
int Int(const su2double &data)
Casts the primitive value to int (uses GetValue, already implemented for each type).
const int MASTER_NODE
Master node for MPI parallelization.
const su2double PI_NUMBER
Pi number.
@ NO
Boolean definition of no.
@ YES
Boolean definition of yes.
@ SU2_DEF
Running the SU2_DEF software.
@ SU2_CFD
Running the SU2_CFD software.
@ PARAVIEW
Paraview ASCII format for the solution output.
const unsigned short COMM_TYPE_CHAR
Communication type for char.
const su2double EPS
Error scale.
const unsigned short N_POINTS_LINE
General output & CGNS defines.
const unsigned short N_POINTS_QUADRILATERAL
General output & CGNS defines.
const unsigned short N_POINTS_PYRAMID
General output & CGNS defines.
const unsigned short COMM_TYPE_UNSIGNED_LONG
Communication type for unsigned long.
@ INCOMPRESSIBLE
Definition of incompressible solver.
@ COMPRESSIBLE
Definition of compressible solver.
@ TWOD_AIRFOIL
Airfoil analysis.
@ NACELLE
Nacelle analysis.
@ WING
Wing analysis.
@ FUSELAGE
Fuselage analysis.
const unsigned int MESH_0
Definition of the finest grid level.
@ VERTEX
VTK nomenclature for defining a vertex element.
@ TRIANGLE
VTK nomenclature for defining a triangle element.
@ PYRAMID
VTK nomenclature for defining a pyramid element.
@ PRISM
VTK nomenclature for defining a prism element.
@ QUADRILATERAL
VTK nomenclature for defining a quadrilateral element.
@ HEXAHEDRON
VTK nomenclature for defining a hexahedron element.
@ LINE
VTK nomenclature for defining a line element.
@ TETRAHEDRON
VTK nomenclature for defining a tetrahedron element.
const unsigned short COMM_TYPE_LONG
Communication type for long.
@ CENTRIPETAL
centripetal turbomachinery.
@ AXIAL
axial turbomachinery.
@ CENTRIPETAL_AXIAL
mixed flow turbine.
@ CENTRIFUGAL
centrifugal turbomachinery.
@ AXIAL_CENTRIFUGAL
mixed flow turbine.
@ HARMONIC_BALANCE
Use a harmonic balance source term.
@ DT_STEPPING_1ST
Use a dual time stepping strategy for unsteady computations (1st order).
@ DT_STEPPING_2ND
Use a dual time stepping strategy for unsteady computations (2nd order).
@ DISC_ADJ_FEM_RANS
@ FEM_NAVIER_STOKES
Definition of the finite element Navier-Stokes' solver.
@ DISC_ADJ_FEM_NS
@ DISC_ADJ_RANS
@ DISC_ADJ_FEM_EULER
@ FEM_RANS
Definition of the finite element Reynolds-averaged Navier-Stokes' (RANS) solver.
@ FEM_EULER
Definition of the finite element Euler's solver.
@ FEM_LES
Definition of the finite element Large Eddy Simulation Navier-Stokes' (LES) solver.
@ FEM_ELASTICITY
Definition of a FEM solver.
@ DISC_ADJ_FEM
const unsigned short N_POINTS_HEXAHEDRON
General output & CGNS defines.
const int SINGLE_ZONE
There is only a zone.
const unsigned short N_POINTS_TETRAHEDRON
General output & CGNS defines.
const unsigned int OVERHEAD
Overhead space above nMarker when allocating space for boundary elems (MPI + periodic).
const int SINGLE_NODE
There is only a node in the MPI parallelization.
const int CGNS_STRING_SIZE
Length of strings used in the CGNS format.
const unsigned short N_POINTS_TRIANGLE
General output & CGNS defines.
const unsigned int MESH_1
Definition of the finest grid level.
@ INTERNAL_BOUNDARY
Internal Boundary definition.
@ EULER_WALL
Boundary Euler wall definition.
@ ISOTHERMAL
No slip isothermal wall boundary condition.
@ TRANSPIRATION
Transpiration definition.
@ SEND_RECEIVE
Boundary send-receive definition.
@ INLET_FLOW
Boundary inlet flow definition.
@ ACTDISK_OUTLET
Actuator disk outlet boundary definition.
@ HEAT_FLUX
No slip constant heat flux wall boundary condition.
@ DISPLACEMENT_BOUNDARY
Boundary displacement definition.
@ NEARFIELD_BOUNDARY
Near-Field boundary definition.
@ INTERFACE_BOUNDARY
Domain interface boundary definition.
@ CHT_WALL_INTERFACE
Domain interface definition.
@ LOAD_BOUNDARY
Boundary Load definition.
@ ACTDISK_INLET
Actuator disk inlet boundary definition.
@ PERIODIC_BOUNDARY
Periodic boundary definition.
@ AUTOMATIC
number of span-wise section are computed automatically
const unsigned int MAX_STRING_SIZE
Maximum number of domains.
@ INFLOW
flag for inflow marker for compute turboperformance.
@ OUTFLOW
flag for outflow marker for compute turboperformance.
const unsigned int MAX_NUMBER_PERIODIC
Maximum number of periodic boundary conditions.
const unsigned short COMM_TYPE_SHORT
Communication type for short.
const unsigned short COMM_TYPE_DOUBLE
Communication type for double.
@ SST
Kind of Turbulence model (Menter SST).
@ SA_NEG
Kind of Turbulent model (Spalart-Allmaras).
@ SA
Kind of Turbulent model (Spalart-Allmaras).
const unsigned short N_POINTS_PRISM
General output & CGNS defines.
@ BC
Kind of transition model (BAS-CAKMAKCIOGLU (BC) for Spalart-Allmaras).
const unsigned short COMM_TYPE_INT
Communication type for int.
@ CGNS
CGNS input format for the computational grid.
@ SU2
SU2 input format.
const unsigned short COMM_TYPE_UNSIGNED_SHORT
Communication type for unsigned short.
@ US
Definition of incompressible solver.
@ SI
Definition of compressible solver.
@ ALLOCATE
Allocate geometry structure.
@ UPDATE
Update geometry structure (grid moving, adaptation, etc.).